

#include "studiox_includes.h"
#include "system_pngs.h"

extern "C"{
#include "gx_utility.h"
#include "gx_api.h"
extern GX_FONT _gx_system_font_8bpp;
extern GX_FONT _gx_system_font_4bpp;
extern GX_FONT _gx_system_font_mono;
extern GX_FONT _gx_dave2d_system_font_4bpp;
extern GX_FONT _gx_dave2d_system_font_mono;
}

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CString ResourceCommentBlock(""
    "/*******************************************************************************/\n"
    "/*  This file is auto-generated by Azure RTOS GUIX Studio. Do not edit this    */\n"
    "/*  file by hand. Modifications to this file should only be made by running    */\n"
    "/*  the Azure RTOS GUIX Studio application and re-generating the application   */\n"
    "/*  resource file(s). For more information please refer to the Azure RTOS GUIX */\n"
    "/*  Studio User Guide, or visit our web site at azure.com/rtos                 */\n"
    "/*                                                                             */\n"
);

#define COLUMN_WIDTH 80
#define GX_CONVERT_VER    1
#define GX_CONVERT_SUBVER 0

static TCHAR *strColorFormat51[] = {
	_T(""),
	_T("GX_COLOR_FORMAT_MONOCHROME"),
	_T("GX_COLOR_FORMAT_MONOCHROME_INVERTED"),
	_T("GX_COLOR_FORMAT_2BIT_GRAY"),
	_T("GX_COLOR_FORMAT_2BIT_GRAY_INVERTED"),
	_T("GX_COLOR_FORMAT_4BIT_GRAY"),
	_T("GX_COLOR_FORMAT_4BIT_GRAY_INVERTED"),
	_T("GX_COLOR_FORMAT_4BIT_VGA"),
	_T("GX_COLOR_FORMAT_8BIT_GRAY"),
	_T("GX_COLOR_FORMAT_8BIT_GRAY_INVERTED"),
	_T("GX_COLOR_FORMAT_8BIT_PALETTE"),
	_T("GX_COLOR_FORMAT_8BIT_PACKED_PIXEL"),
	_T("GX_COLOR_FORMAT_15BIT_BGR"),
	_T("GX_COLOR_FORMAT_15BIT_RGB"),
	_T("GX_COLOR_FORMAT_16BIT_RGB"),
    _T("GX_COLOR_FORMAT_16BIT_ARGB"),
    _T("GX_COLOR_FORMAT_16BIT_BGRA"),
	_T("GX_COLOR_FORMAT_16BIT_BGR"),
	_T("GX_COLOR_FORMAT_24BIT_RGB"),
	_T("GX_COLOR_FORMAT_24BIT_BGR"),
	_T("GX_COLOR_FORMAT_24BIT_XRGB"),
	_T("GX_COLOR_FORMAT_24BIT_BGRX"),
	_T("GX_COLOR_FORMAT_32BIT_ARGB"),
	_T("GX_COLOR_FORMAT_32BIT_RGBA"),
	_T("GX_COLOR_FORMAT_32BIT_ABGR"),
	_T("GX_COLOR_FORMAT_32BIT_BGRA"),
};

static TCHAR *strColorFormat52[] = {
	_T(""),
	_T("GX_COLOR_FORMAT_MONOCHROME"),
	_T("GX_COLOR_FORMAT_MONOCHROME_INVERTED"),
	_T("GX_COLOR_FORMAT_2BIT_GRAY"),
	_T("GX_COLOR_FORMAT_2BIT_GRAY_INVERTED"),
	_T("GX_COLOR_FORMAT_4BIT_GRAY"),
	_T("GX_COLOR_FORMAT_4BIT_GRAY_INVERTED"),
	_T("GX_COLOR_FORMAT_4BIT_VGA"),
	_T("GX_COLOR_FORMAT_8BIT_GRAY"),
	_T("GX_COLOR_FORMAT_8BIT_GRAY_INVERTED"),
	_T("GX_COLOR_FORMAT_8BIT_PALETTE"),
	_T("GX_COLOR_FORMAT_8BIT_PACKED_PIXEL"),
	_T("GX_COLOR_FORMAT_5551BGRX"),
	_T("GX_COLOR_FORMAT_1555XRGB"),
	_T("GX_COLOR_FORMAT_565RGB"),
    _T("GX_COLOR_FORMAT_4444ARGB"),
    _T("GX_COLOR_FORMAT_4444BGRA"),
	_T("GX_COLOR_FORMAT_565BGR"),
	_T("GX_COLOR_FORMAT_24RGB"),
	_T("GX_COLOR_FORMAT_24BGR"),
	_T("GX_COLOR_FORMAT_24XRGB"),
	_T("GX_COLOR_FORMAT_24BGRX"),
	_T("GX_COLOR_FORMAT_32ARGB"),
	_T("GX_COLOR_FORMAT_32RGBA"),
	_T("GX_COLOR_FORMAT_32ABGR"),
	_T("GX_COLOR_FORMAT_32BGRA"),
    _T("GX_COLOR_FORMAT_8BIT_ALPHAMAP"),
};

#define NUM_COLOR_FORMATS (sizeof(strColorFormat52) / sizeof(TCHAR *))

#define IS_RX_TARGET      (m_project->mHeader.target_cpu == CPU_RX)
#define IS_RZ_TARGET      (m_project->mHeader.target_cpu == CPU_RZ)
#define IS_GNU_TOOLS      (m_project->mHeader.target_tools == TOOLS_GNU)
#define IS_IAR_TOOLS      (m_project->mHeader.target_tools == TOOLS_IAR)

////////////////////////////////////////////////////////////////////////////////////////////////
resource_gen::resource_gen(studiox_project *proj)
{
    m_project = proj;   
    m_num_displays = m_project->mHeader.num_displays;
    mUsingDefault8BitFont = FALSE;
    mUsingDefault4BitFont = FALSE;
    mUsingDefaultMonoFont = FALSE;

    if (GetCmdInfo()->IsNoGui())
    {
        m_big_endian = GetCmdInfo()->IsBigEndian();
    }
    else
    {
        m_big_endian = m_project->mHeader.big_endian;
    }

    mp_bin_generater = NULL;
    m_warn_on_error = FALSE;
}

///////////////////////////////////////////////////////////////////////////////
//
// IsRotatedResourceSupported
//
// Static function used by resource_gen, binary_resource_gen, and 
// screen generator to determine if screen rotation support is enabled.
///////////////////////////////////////////////////////////////////////////////

BOOL resource_gen::IsRotatedResourceSupported(studiox_project *project, int display)
{
    #if !defined(ENABLE_RENESAS_DAVE2D_DISPLAY_ROTATION)
    if (project->mHeader.target_cpu == CPU_SYNERGY)
    {
        return FALSE;
    }
    #endif

    if (project->mDisplays[display].rotation_angle == GX_SCREEN_ROTATION_CW ||
        project->mDisplays[display].rotation_angle == GX_SCREEN_ROTATION_CCW)
    {
        switch (project->mDisplays[display].colorformat)
        {
        case GX_COLOR_FORMAT_565RGB:
            if (project->mHeader.guix_version >= GX_VERSION_DISPLAY_ROTATION)
            {
                return TRUE;
            }
            break;

        case GX_COLOR_FORMAT_8BIT_PALETTE:
            if (project->mHeader.guix_version >= GX_VERSION_8BIT_PALETTE_DISPLAY_ROTATION)
            {
                return TRUE;
            }
            break;

        case GX_COLOR_FORMAT_24XRGB:
        case GX_COLOR_FORMAT_32ARGB:
            if (project->mHeader.guix_version >= GX_VERSION_8BIT_PALETTE_DISPLAY_ROTATION)
            {
                return TRUE;
            }
            break;
        }
    }

    return FALSE;
}



////////////////////////////////////////////////////////////////////////////////////////////////
BOOL resource_gen::SetOutFile(CString filename, BOOL binary_mode)
{
    CString pathname;
    PATHINFO info;

    CString outfile = m_project->mHeader.resource_path;
    if (outfile.GetAt(outfile.GetLength() - 1) != '\\')
    {
        outfile += '\\';
    }
    outfile += filename;
    
    if (outfile.GetAt(1) != ':')
    {
        ConvertToProjectRelativePath(outfile);

        info.pathname = outfile;
        info.pathtype = PATH_TYPE_PROJECT_RELATIVE;

        outfile = MakeAbsolutePathname(info);
    }

    if (!CheckOutputFileSecurity(outfile, binary_mode))
    {
        return FALSE;
    }

    for (int index = 0; index < outfile_list.GetCount(); index++)
    {
        m_outfile = outfile_list.GetAt(index);
        
        pathname = m_outfile->GetFilePath();

        if (!outfile.Compare(pathname))
        {
            m_written_size = (ULONG)m_outfile->GetLength();

            return TRUE;
        }
    }

    m_outfile = new CFile();
    m_written_size = 0;
    if (!m_outfile->Open(outfile, CFile::modeCreate | CFile::modeWrite))
    {
        CString msg;
        msg.Format(_T("Could not open output file:\n%s\nPlease check resource file path."), outfile);
        ErrorMsg(msg);
        delete m_outfile;
        return FALSE;
    }

    outfile_list.Add(m_outfile);

    if (binary_mode)
    {
        ((binary_resource_gen *)this)->WriteStandaloneResHeader();
    }
    else
    {
        WriteCommentBlock(ResourceCommentBlock);
        CString out;

        if (m_project->mHeader.insert_headers_before)
        {
            // Insert additional headers before any other includes
            WriteAdditionalHeaders(m_project->mHeader.additional_headers);
        }

        out.Format(_T("#include \"gx_api.h\"\n#include \"%s.h\"\n"), GetResourceFileName());
        FileWrite(out);

        if (!m_project->mHeader.insert_headers_before)
        {
            //Insert additional headers after any other includes
            WriteAdditionalHeaders(m_project->mHeader.additional_headers);
        }
    }

    return TRUE;
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteErrorDirectives()
{
    CCommandInfo *pCmdInfo = GetCmdInfo();
    BOOL enabled;
    BOOL UTF8 = FALSE;
    BOOL EXTENDED_UNICODE = FALSE;
    BOOL KERNING = FALSE;
    CString out;

    for (int theme = 0; theme < m_project->mDisplays[m_display].num_themes; theme++)
    {
        m_ThemeName = m_project->mDisplays[m_display].themes[theme].theme_name;

        if (pCmdInfo->IsNoGui())
        {
            enabled = pCmdInfo->IsThemeEnabled(m_ThemeName);
        }
        else
        {
            enabled = m_project->mDisplays[m_display].themes[theme].gen_font_table;
        }

        if (!enabled) continue;

        int font_id;

        for (font_id = 0; font_id < m_project->CountResources(m_display, RES_TYPE_FONT); font_id++)
        {
            res_info *info = m_project->FindResource(m_display, theme, RES_TYPE_FONT, font_id);

            if (info)
            {
                if (!KERNING && info->font_kerning)
                {
                    KERNING = TRUE;
                }

                if ((!UTF8 || !EXTENDED_UNICODE) && !(info->is_default && info->pathinfo.pathname.IsEmpty()))
                {
                    if (info->font_support_extended_unicode)
                    {
                        EXTENDED_UNICODE = TRUE;
                        UTF8 = TRUE;
                    }
                    else
                    {
                        
                        GX_FONT *next_page = m_optimized_fonts[theme].GetAt(font_id);
                        
                        if(!next_page)
                        {
                            next_page = MakeOptimizedFont(info, m_display, m_warn_on_error);

                            if (!next_page)
                            {
                                m_warn_on_error = FALSE;
                            }

                            // Reserve optimized font for later use.
                        	m_optimized_fonts[theme].SetAt(font_id, next_page);
                        }

                        while (next_page)
                        {
                            if (next_page->gx_font_last_glyph > 0xffff)
                            {
                                EXTENDED_UNICODE = TRUE;
                                UTF8 = TRUE;
                                break;
                            }
                            else if (next_page->gx_font_last_glyph > 0xff)
                            {
                                UTF8 = TRUE;
                            }

                            next_page = (GX_FONT *)next_page->gx_font_next_page;
                        }
                    }
                }
            }
        }

        if (EXTENDED_UNICODE && KERNING)
        {
            break;
        }
    }

    out = "";
    if (UTF8)
    {
        out += _T("\n#if !defined(GX_UTF8_SUPPORT)\n");
        out += _T("#error \"The symbol GX_UTF8_SUPPORT must be defined to support the Studio project settings\".\n");
        out += _T("#endif\n");
    }

    if (EXTENDED_UNICODE)
    {
        out += _T("#if !defined(GX_EXTENDED_UNICODE_SUPPORT)\n");
        out += _T("#error \"The symbol GX_EXTENDED_UNICODE_SUPPORT must be defined to support the Studio project settings\".\n");
        out += _T("#endif\n");
    }

    if (KERNING)
    {
        out += _T("#if !defined(GX_FONT_KERNING_SUPPORT)\n");
        out += _T("#error \"The symbol GX_FONT_KERNING_SUPPORT must be defined if \'Generate kerning info\' is selected in font edit dialog\".\n");
        out += _T("#endif\n");
    }

    FileWrite(out);
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::CalculateTableSizes()
{
    /* Calculate the size of color table, font table and pixelmap table. */
    m_color_table_size = m_font_table_size = m_pixelmap_table_size = 0;
    int active_theme = m_project->mDisplays[m_display].active_theme;
    int res_id;
    res_info *info;
    m_color_table_size = m_project->CountResources(m_display, RES_TYPE_COLOR);

    for (res_id = 0; res_id < m_project->CountResources(m_display, RES_TYPE_FONT); res_id++)
    {
        info = m_project->FindResource(m_display, active_theme, RES_TYPE_FONT, res_id);

        if (IsResEnabled(info) && (!info->output_file_enabled || !info->binary_mode))
        {
            m_font_table_size++;
        }
    }

    m_pixelmap_table_size = 1;

    for (res_id = 1; res_id <= m_project->CountResources(m_display, RES_TYPE_PIXELMAP); res_id++)
    {
        info = m_project->FindResource(m_display, active_theme, RES_TYPE_PIXELMAP, res_id);

        if ((IsResEnabled(info) && (!info->output_file_enabled || !info->binary_mode)) || IsSystemPixelmap(res_id))
        {
            m_pixelmap_table_size += info->GetPixelmapFrameCount();
        }
    }
}

///////////////////////////////////////////////////////////////////////////////
BOOL resource_gen::IsStringReferencedbyMlView(widget_info* info, GX_RESOURCE_ID resource_id)
{
    while (info)
    {

        if ((info->basetype == GX_TYPE_MULTI_LINE_TEXT_VIEW) &&
            (info->string_id[0] == resource_id))
        {
            return TRUE;
        }

        if (IsStringReferencedbyMlView(info->GetChildWidgetInfo(), resource_id))
        {
            return TRUE;
        }

        info = info->GetNextWidgetInfo();
    }
    return FALSE;
}

////////////////////////////////////////////////////////////////////////////////////////////////
BOOL resource_gen::GenerateResourceFile(int display)
{
    m_display = display;
    mDefaultPaletteWritten = FALSE;

    GotoProjectDirectory();

    // for now just use project name for output name
    CCommandInfo *pCmdInfo = GetCmdInfo();
    CString res_file_name;
    BOOL    gen_res_header;

    if (m_outfile)
    {
        delete m_outfile;
    }

    InitOptimizedFonts();

    m_outfile = new CFile();

    CalculateTableSizes();

    if (pCmdInfo->IsNoGui())
    {
        gen_res_header = pCmdInfo->GenResHeader();
    }
    else
    {
        gen_res_header = m_project->mHeader.gen_res_header;
    }

    m_project->CopyDictionary(m_display, RES_TYPE_PIXELMAP, &m_pixelmap_dictionary);
    m_project->SortResDictionary(RES_TYPE_PIXELMAP, &m_pixelmap_dictionary);

    if (gen_res_header)
    {
        res_file_name = m_project->mHeader.header_path;
        if (!res_file_name.IsEmpty())
        {
            if (res_file_name.GetAt(res_file_name.GetLength() - 1) != '\\')
            {
                res_file_name += "\\";
            }
        }

        res_file_name += GetResourceFileName() + _T(".h");
        if (!CheckOutputFileSecurity(res_file_name))
        {
            return FALSE;
        }

        /* Generate head file. */
        if (!m_outfile->Open(res_file_name, CFile::modeCreate | CFile::modeWrite))
        {
            CString msg;
            msg.Format(_T("Could not open output file:\n%s\nPlease check resource file path."), res_file_name);

            ErrorMsg(msg);
            delete m_outfile;
            DestroyOptimizedFonts();
            return FALSE;
        }

        GenerateResourceHeader();
        m_outfile->Close();
    }

    res_file_name = m_project->mHeader.resource_path;
    if (!res_file_name.IsEmpty())
    {
        if (res_file_name.GetAt(res_file_name.GetLength() - 1) != '\\')
        {
            res_file_name += "\\";
        }
    }

    res_file_name += GetResourceFileName() + _T(".c");

    /* Generate c file. */
    if (!m_outfile->Open(res_file_name, CFile::modeCreate | CFile::modeWrite))
    {
        CString msg;
        msg.Format(_T("Could not open output file:\n%s\nPlease check resource file path."), res_file_name);

        ErrorMsg(msg);
        EndBusyMsg();
        delete m_outfile;
        DestroyOptimizedFonts();
        return FALSE;
    }
    outfile_list.Add(m_outfile);

    if (pCmdInfo->IsXmlMode())
    {
        WriteFontData();
        WritePixelmapData();
    }
    else
    {
        GenerateResourceData();
    }
    DestroyOptimizedFonts();
    CloseOutputFiles();

    if (mp_bin_generater)
    {
        mp_bin_generater->DestroyResource();
        delete mp_bin_generater;
        mp_bin_generater = NULL;
    }

    return TRUE;
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::CloseOutputFiles()
{
    for (int index = 0; index < outfile_list.GetCount(); index++)
    {
        m_outfile = outfile_list.GetAt(index);
        m_outfile->Close();
        delete m_outfile;
    }
    m_outfile = NULL;
    outfile_list.RemoveAll();
}

////////////////////////////////////////////////////////////////////////////////////////////////
CString resource_gen::UpperProjectName()
{
    CString name(m_project->mHeader.project_name);
    name.MakeUpper();
    return name;
}


////////////////////////////////////////////////////////////////////////////////////////////////
CString resource_gen::UpperProjDisplayName()
{
    CString name(m_project->mHeader.project_name);
    name += "_";
    name += m_project->mDisplays[m_display].name;
    name.MakeUpper();
    return name;
}

////////////////////////////////////////////////////////////////////////////////////////////////
BOOL resource_gen::GenerateResourceHeader()
{
    WriteCommentBlock(ResourceCommentBlock);

    CString out;
    CString name;

    name = UpperProjDisplayName();

    out.Format(_T("#ifndef _%s_RESOURCES_H_\n#define _%s_RESOURCES_H_\n\n"), name, name);
    FileWrite(out);
    FileWrite(CString("#include \"gx_api.h\"\n"));

    WriteErrorDirectives();

    WriteDisplayDefines();
    WriteThemeDefines();
    WriteLanguageDefines();

    WriteColorDefines();
    WriteFontDefines();
    WritePixelmapDefines();

    WriteStringDefines();

    FileWrite(CString("\n#endif      /* sentry */\n"));
   
    return TRUE;
}

////////////////////////////////////////////////////////////////////////////////////////////////
BOOL resource_gen::GenerateResourceData()
{
    string_table *table = GetActiveStringTable();
    if (table)
    {
        table->GenerateCleanCharacterMap();
    }
    WriteCommentBlock(ResourceCommentBlock);
    CString out;

    if (m_project->mHeader.insert_headers_before)
    {
        //Insert additional headers before any other includes
        WriteAdditionalHeaders(m_project->mHeader.additional_headers);
    }

    out.Format(_T("#include \"gx_api.h\"\n#include \"%s.h\"\n"), GetResourceFileName());
    FileWrite(out);

    if (!m_project->mHeader.insert_headers_before)
    {
        WriteAdditionalHeaders(m_project->mHeader.additional_headers);
    }

    WriteColorTable();
    WriteFontData();
    WriteFontTable();
    WritePixelmapData();
    WritePixelmapTable();
    WriteStringData();
    WriteStringTable();

    WriteThemes();

    return TRUE;
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::InitOptimizedFonts()
{
    int font_count = m_project->CountResources(m_display, RES_TYPE_FONT);
    for (int theme = 0; theme < m_project->mDisplays[m_display].num_themes; theme++)
    {
        m_optimized_fonts[theme].RemoveAll();

        for (int index = 0; index < font_count; index++)
        {
            m_optimized_fonts[theme].Add(GX_NULL);
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::DestroyOptimizedFonts()
{
    GX_FONT* font;

    for (int theme = 0; theme < m_project->mDisplays[m_display].num_themes; theme++)
    {
        for (int index = 0; index < m_optimized_fonts[theme].GetCount(); index++)
        {
            font = m_optimized_fonts[theme].GetAt(index);
            if (font)
            {
                DestroyFont(font);
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
TCHAR **resource_gen::GetColorFormatTable(studiox_project *project)
{
    TCHAR** format_name = strColorFormat52;

    /* switch for backward compatibility */
    if (project->mHeader.guix_version < 50200)
    {
        format_name = strColorFormat51;
    }

    return format_name;
}
////////////////////////////////////////////////////////////////////////////////////////////////
TCHAR *resource_gen::GetColorFormatName(int color_format)
{
    if (color_format >= NUM_COLOR_FORMATS)
    {
        ErrorMsg("Invalid color format in project header");
        return(_T("INVALID_FORMAT"));
    }

    studiox_project* project = GetOpenProject();

    if (!project)
    {
        return L"";
    }

    return(GetColorFormatTable(project)[color_format]);
}

////////////////////////////////////////////////////////////////////////////////////////////////
int resource_gen::GetColorFormatVal(CString name)
{
    if (name.IsEmpty())
    {
        return 0;
    }

    studiox_project* project = GetOpenProject();

    if (!project)
    {
        return 0;
    }

    TCHAR** table = GetColorFormatTable(project);

    for(int index = 0; index < NUM_COLOR_FORMATS; index++)
    {
        if (CString(table[index]) == name)
        {
            return index;
        }
    }

    return 0;
}


////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteDisplayDefines()
{
    CString out;

    WriteComment("Display and theme definitions");

    out.Format(_T("#define %s %d\n"), UpperDisplayName(), m_display);
    FileWrite(out);

    out.Format(_T("#define %s_COLOR_FORMAT %s\n"), UpperDisplayName(), GetColorFormatName(m_project->mDisplays[m_display].colorformat));
    FileWrite(out);

    out.Format(_T("#define %s_X_RESOLUTION %d\n"), UpperDisplayName(), m_project->mDisplays[m_display].xres);
    FileWrite(out);
    out.Format(_T("#define %s_Y_RESOLUTION %d\n"), UpperDisplayName(), m_project->mDisplays[m_display].yres);
    FileWrite(out);
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteThemeDefines()
{
    /* Pickup command info class instance. */
    CCommandInfo *pCmdInfo = GetCmdInfo();
    theme_info *info;
    CString theme_name;
    BOOL enabled;
    CString out;
    int theme_count = 0;

    for (int theme = 0; theme < m_project->mDisplays[m_display].num_themes; theme++)
    {
        info = &(m_project->mDisplays[m_display].themes[theme]);
        theme_name = info->theme_name;

        if (pCmdInfo->IsNoGui())
        {
            enabled = pCmdInfo->IsThemeEnabled(theme_name);
        }
        else
        {
            enabled = info->enabled;
        }

        // Include the definitions of enabled themes
        if (enabled)
        {

            theme_name.MakeUpper();
            out.Format(_T("#define %s_%s %d\n"), UpperDisplayName(), theme_name, theme_count);
            FileWrite(out);

            theme_count++;
        }
    }

    if (m_project->mHeader.guix_version > 50302)
    {
        if (theme_count)
        {
            out.Format(_T("#define %s_THEME_TABLE_SIZE %d\n"), UpperDisplayName(), theme_count);
            FileWrite(out);
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteLanguageDefines()
{
    CString out;

    INT language_count = 0;

    WriteComment("Language definitions");

    /* Pickup command info class instance. */
    CCommandInfo *pCmdInfo = GetCmdInfo();
    CString lang_name;
    BOOL enabled;
    CString display_name;

    if (m_project->mHeader.num_displays > 1)
    {
        display_name = UpperDisplayName() + _T("_");
    }
    else
    {
        display_name = _T("");
    }

    for (int language = 0; language < m_project->mHeader.num_languages; language++)
    {
        lang_name = m_project->mHeader.languages[language].name;

        if (pCmdInfo->IsNoGui())
        {
            enabled = pCmdInfo->IsLanguageEnabled(lang_name);
        }
        else
        {
            enabled = m_project->mDisplays[m_display].gen_string_table[language];
        }

        /* Include the definicions of enabled languages. */
        if(enabled)
        {
            lang_name.MakeUpper();

            out.Format(_T("#define %sLANGUAGE_%s %d\n"), display_name, lang_name, language_count);
            FileWrite(out);

            language_count++;
        }
    }

    if (language_count)
    {
        out.Format(_T("#define %s_LANGUAGE_TABLE_SIZE %d\n"), UpperDisplayName(), language_count);
        FileWrite(out);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteColorDefines(void)
{
    int color_id;
    int active_theme = m_project->mDisplays[m_display].active_theme;
    WriteComment("Color ID definitions");
    CString out;
    CString res_name;
    CString upper_name;
    CString display_name = UpperDisplayName();
    BOOL gen_system_color_ids = FALSE;

    if (project_lib_version() < GX_VERSION_RESOURCE_ID_GENERATE_FIX)
    {
        gen_system_color_ids = TRUE;
    }
    

    for (color_id = 0; color_id < m_project->CountResources(m_display, RES_TYPE_COLOR); color_id++)
    {
        res_info *info = m_project->FindResource(m_display, active_theme, RES_TYPE_COLOR, color_id);
        if (info)
        {
            upper_name = CString(info->name);
            upper_name.MakeUpper();

            if (info->is_default)
            {
                if ((m_display == 0) && gen_system_color_ids)
                {
                    out.Format(_T("#define GX_COLOR_ID_%s %d\n"), upper_name, color_id);
                    FileWrite(out);
                }
            }
            else
            {
                if (m_num_displays > 1)
                {
                    out.Format(_T("#define GX_COLOR_ID_%s_%s %d\n"), display_name, upper_name, color_id);
                }
                else
                {
                    out.Format(_T("#define GX_COLOR_ID_%s %d\n"), upper_name, color_id);
                }
                FileWrite(out);
            }
        }
    }

    out.Format(_T("#define %s_COLOR_TABLE_SIZE %d\n"),
        display_name, m_color_table_size);
    FileWrite(out);
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteColorTable(void)
{
    int color_id;
    res_info *info;
    WriteComment("Color Table");
    CString out;
    GX_COLOR rgb_color;
    GX_COLOR native_color;
    int color_format;

    color_format = m_project->mDisplays[m_display].colorformat;

    CCommandInfo *pCmdInfo = GetCmdInfo();
    BOOL enabled;

    for (int theme = 0; theme < m_project->mDisplays[m_display].num_themes; theme++)
    {
        if (pCmdInfo->IsNoGui())
        {
            enabled = pCmdInfo->IsThemeEnabled(m_project->mDisplays[m_display].themes[theme].theme_name);
        }
        else
        {
            enabled = m_project->mDisplays[m_display].themes[theme].gen_color_table;
        }

        if (!enabled) continue;

        out.Format(_T("GX_CONST GX_COLOR %s_%s_color_table[] =\n{\n"),
            m_project->mDisplays[m_display].name,
            m_project->mDisplays[m_display].themes[theme].theme_name);
        FileWrite(out);

        int end_id = m_project->CountResources(m_display, RES_TYPE_COLOR);
        BOOL bFirstColor = TRUE;

        for (color_id = 0; color_id < end_id; color_id++)
        {
            info = m_project->FindResource(m_display, theme, RES_TYPE_COLOR, color_id);

            if (info)
            {
                rgb_color = info->colorval;
                native_color = resource_view::GetNativeColor(rgb_color, color_format);

                if (bFirstColor)
                {
                    out.Format(_T("    0x%08x"), native_color);
                    bFirstColor = FALSE;
                }
                else
                {
                    out.Format(_T(",\n    0x%08x"), native_color);
                }
                FileWrite(out);
            }
        }
        out.Format(_T("\n};\n\n"));
        FileWrite(out);

        /* Olny write palette for 8bit palette driver for now.
           4bpp driver contains palette table. But should not write it to file. */
        if (color_format == GX_COLOR_FORMAT_8BIT_PALETTE &&
            m_project->mDisplays[m_display].themes[theme].palette)
        {
            WritePalette(theme);
            mDefaultPaletteWritten = TRUE;
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WritePalette(int theme)
{
    GX_COLOR *palette;
    int palette_size;

    // make sure the optimal palette is up to date:
    m_project->CreateThemePalette(m_display, theme, NULL);

    // CreateThemePalette() updates the display.themes.palette

    palette_size = m_project->mDisplays[m_display].themes[theme].palette_total_size;
    palette =  m_project->mDisplays[m_display].themes[theme].palette;

    WritePalette(palette_size, palette, m_project->mDisplays[m_display].themes[theme].theme_name);
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WritePalette(int palette_size, GX_COLOR *palette,
    CString &pal_name)
{
    CString out;
    int palette_index;

    WriteComment("Color Palette");
    GX_COLOR rgb_color;

    if (palette == NULL || palette_size == 0)
    {
        return;
    }

    out.Format(_T("GX_CONST GX_COLOR %s_%s_palette[%d] =\n{\n"),
         m_project->mDisplays[m_display].name, pal_name, palette_size);
    FileWrite(out);

    for (palette_index = 0; palette_index < palette_size; palette_index++)
    {
        rgb_color = palette[palette_index];

        if (palette_index < palette_size - 1)
        {
            out.Format(_T("    0x%08x,\n"), rgb_color);
        }
        else
        {
            out.Format(_T("    0x%08x\n"), rgb_color);
        }
        FileWrite(out);
    }
    out.Format(_T("};\n\n"));
    FileWrite(out);
}


////////////////////////////////////////////////////////////////////////////////////////////////
CString resource_gen::UpperDisplayName()
{
    CString upper_name =  m_project->mDisplays[m_display].name;
    upper_name.MakeUpper();
    return upper_name;
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteFontDefines(void)
{
    int font_id;
    int active_theme = m_project->mDisplays[m_display].active_theme;
    WriteComment("Font ID definitions");
    CString out;
    CString upper_name;
    BOOL gen_system_font_ids = FALSE;

    if (project_lib_version() < GX_VERSION_RESOURCE_ID_GENERATE_FIX)
    {
        gen_system_font_ids = TRUE;
    }

    for (font_id = 0; font_id < m_project->CountResources(m_display, RES_TYPE_FONT); font_id++)
    {
        res_info *info = m_project->FindResource(m_display, active_theme, RES_TYPE_FONT, font_id);
        if (info && (!info->output_file_enabled || !info->binary_mode))
        {
            CString upper_name(info->name);
            upper_name.MakeUpper();

            if (info->is_default)
            {
                if ((m_display == 0) && gen_system_font_ids)
                {
                    out.Format(_T("#define GX_FONT_ID_%s %d\n"), upper_name, font_id);
                    FileWrite(out);
                }
            }
            else
            {
                if (m_num_displays > 1)
                {
                    out.Format(_T("#define GX_FONT_ID_%s_%s %d\n"), UpperDisplayName(), upper_name, font_id);
                }
                else
                {
                    out.Format(_T("#define GX_FONT_ID_%s %d\n"), upper_name, font_id);
                }
                FileWrite(out);
            }
        }
    }

    out.Format(_T("#define %s_FONT_TABLE_SIZE %d\n"),
       UpperDisplayName(), m_font_table_size);
    FileWrite(out);

}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteFontData(void)
{
    int font_id;
    mUsingDefault8BitFont = FALSE;
    mUsingDefault4BitFont = FALSE;
    mUsingDefaultMonoFont = FALSE;

    CCommandInfo *pCmdInfo = GetCmdInfo();
    BOOL enabled;
    
    for (int theme = 0; theme < m_project->mDisplays[m_display].num_themes; theme++)
    {
        m_ThemeName = m_project->mDisplays[m_display].themes[theme].theme_name;

        if (pCmdInfo->IsNoGui())
        {
            enabled = pCmdInfo->IsThemeEnabled(m_ThemeName);
        }
        else
        {
            enabled = m_project->mDisplays[m_display].themes[theme].gen_font_table;
        }

        if (!enabled) continue;

        for (font_id = 0; font_id < m_project->CountResources(m_display, RES_TYPE_FONT); font_id++)
        {
            res_info *info = m_project->FindResource(m_display, theme, RES_TYPE_FONT, font_id);
            CString out;

            if (info)
            {
                INT rotation_angle = m_project->mDisplays[m_display].rotation_angle;

                if (info->is_default &&
                    info->pathinfo.pathname.IsEmpty() &&
                    !IsRotatedResourceSupported(m_project, m_display))
                {
                    switch (info->font_bits)
                    {
                    case 8:
                        mUsingDefault8BitFont = TRUE;
                        break;

                    case 4:
                        mUsingDefault4BitFont = TRUE;
                        break;

                    case 1:
                        mUsingDefaultMonoFont = TRUE;
                        break;
                    }
                }
                else
                {
                    if (FindResourceReferenceTheme(info, theme) == -1)
                    {
                        if ((!info->pathinfo.pathname.IsEmpty()) ||
                            (rotation_angle != 0))
                        {
                            if (info->output_file_enabled)
                            {
                                if (info->binary_mode)
                                {
                                    if (!mp_bin_generater)
                                    {
                                        mp_bin_generater = new binary_resource_gen(m_project, BINARY_FILE_FORMAT_BIN_STANDALONE);
                                        mp_bin_generater->SetDisplay(m_display);
                                        mp_bin_generater->InitResource();
                                    }

                                    if (!mp_bin_generater->SetOutFile(info->output_file, info->binary_mode))
                                    {
                                        return;
                                    }

                                    mp_bin_generater->WriteFontBlock(info, font_id, theme);
                                    continue;
                                }

                                if (!SetOutFile(info->output_file))
                                {
                                    return;
                                }
                            }

                            out.Format(_T("\n/* Font %s_%s Data Definition */\n\n"), m_ThemeName.MakeUpper(), info->name);
                            FileWrite(out);
                            WriteFont(info, theme, font_id);

                            if (info->output_file_enabled)
                            {
                                m_outfile = outfile_list.GetAt(0);
                            }
                        }
                    }
                }
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteFontTable(void)
{
    int font_id;
    WriteComment("Font Table");
    CString out;
    CString name;
    
    if (mUsingDefault8BitFont)
    {
        out = CString("\nextern GX_CONST GX_FONT _gx_system_font_8bpp;\n");
        FileWrite(out);
    }
    if (mUsingDefault4BitFont)
    {
        if (IsDave2dFontFormat(m_project, m_display))
        {
            if (m_project->mHeader.target_cpu == CPU_SYNERGY)
            {
                out = CString("\nextern GX_CONST GX_FONT _gx_synergy_system_font_4bpp;\n");
            }
            else
            {
                out = CString("\nextern GX_CONST GX_FONT _gx_dave2d_system_font_4bpp;\n");
            }
        }
        else
        {
            out = CString("\nextern GX_CONST GX_FONT _gx_system_font_4bpp;\n");
        }
        FileWrite(out);
    }
    if (mUsingDefaultMonoFont)
    {
        if (IsDave2dFontFormat(m_project, m_display))
        {
            if (m_project->mHeader.target_cpu == CPU_SYNERGY)
            {
                out = CString("\nextern GX_CONST GX_FONT _gx_synergy_system_font_mono;\n");
            }
            else
            {
                out = CString("\nextern GX_CONST GX_FONT _gx_dave2d_system_font_mono;\n");
            }
        }
        else
        {
            out = CString("\nextern GX_CONST GX_FONT _gx_system_font_mono;\n");
        }
        FileWrite(out);
    }

    CCommandInfo* pCmdInfo = GetCmdInfo();
    BOOL enabled;
    int end_id = m_project->CountResources(m_display, RES_TYPE_FONT);
    res_info *info;
    CString theme_name;
    int reference_theme;

    /* Extern fonts that defined in custom output files. */
    for (int theme = 0; theme < m_project->mDisplays[m_display].num_themes; theme++)
    {
        m_ThemeName = m_project->mDisplays[m_display].themes[theme].theme_name;

        if (pCmdInfo->IsNoGui())
        {
            enabled = pCmdInfo->IsThemeEnabled(m_ThemeName);
        }
        else
        {
            enabled = m_project->mDisplays[m_display].themes[theme].gen_font_table;
        }

        if (!enabled) continue;

        for (font_id = 0; font_id < end_id; font_id++)
        {
            info = m_project->FindResource(m_display, theme, RES_TYPE_FONT, font_id);

            if (IsResEnabled(info) && (info->output_file_enabled) && (!info->binary_mode))
            {
                theme_name = m_ThemeName;
                reference_theme = FindResourceReferenceTheme(info, theme);
                if (reference_theme >= 0)
                {
                    theme_name = m_project->mDisplays[m_display].themes[reference_theme].theme_name;
                }

                out.Format(_T("extern GX_CONST GX_FONT %s_%s;\n"), theme_name.MakeUpper(), info->name);
                FileWrite(out);
            }
        }
    }

    for (int theme = 0; theme < m_project->mDisplays[m_display].num_themes; theme++)
    {
        m_ThemeName = m_project->mDisplays[m_display].themes[theme].theme_name;

        if (pCmdInfo->IsNoGui())
        {
            enabled = pCmdInfo->IsThemeEnabled(m_ThemeName);
        }
        else
        {
            enabled = m_project->mDisplays[m_display].themes[theme].gen_font_table;
        }

        if (!enabled) continue;


        name = m_project->mDisplays[m_display].name;
        name += "_";
        name += m_project->mDisplays[m_display].themes[theme].theme_name;
        out.Format(_T("GX_CONST GX_FONT *%s_font_table[] =\n{\n"), name);
        FileWrite(out);

        BOOL bFirstFont = TRUE;

        for(font_id = 0; font_id < end_id; font_id++)
        {
            info = m_project->FindResource(m_display, theme, RES_TYPE_FONT, font_id);

            if (info && (!info->output_file_enabled || !info->binary_mode))
            {
                if (info->is_default &&
                    info->pathinfo.pathname.IsEmpty() &&
                    (!IsRotatedResourceSupported(m_project, m_display)))
                {
                    switch (info->font_bits)
                    {
                    case 8:
                        name = "_gx_system_font_8bpp";
                        break;

                    case 4:
                        if (IsDave2dFontFormat(m_project, m_display))
                        {
                            if (m_project->mHeader.target_cpu == CPU_SYNERGY)
                            {
                                name = "_gx_synergy_system_font_4bpp";
                            }
                            else
                            {
                                name = "_gx_dave2d_system_font_4bpp";
                            }
                        }
                        else
                        {
                            name = "_gx_system_font_4bpp";
                        }
                        break;
                    case 1:
                        if (IsDave2dFontFormat(m_project, m_display))
                        {
                            if (m_project->mHeader.target_cpu == CPU_SYNERGY)
                            {
                                name = "_gx_synergy_system_font_mono";
                            }
                            else
                            {
                                name = "_gx_dave2d_system_font_mono";
                            }
                        }
                        else
                        {
                            name = "_gx_system_font_mono";
                        }
                        break;
                    }
                }
                else
                {
                    theme_name = m_ThemeName;
                    reference_theme = FindResourceReferenceTheme(info, theme);
                    if (reference_theme >= 0)
                    {
                        theme_name = m_project->mDisplays[m_display].themes[reference_theme].theme_name;
                    }

                    name.Format(_T("%s_%s"), theme_name.MakeUpper(), info->name);
                }

                if (bFirstFont)
                {
                    out.Format(_T("    &%s"), name);
                    bFirstFont = FALSE;
                }
                else
                {
                    out.Format(_T(",\n    &%s"), name);
                }
                FileWrite(out);
            }
        }
        out.Format(_T("\n};\n"));
        FileWrite(out);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WritePixelmapDefines(void)
{
    int pixelmap_id;
    int output_pixelmap_id = 1;
    int active_theme = m_project->mDisplays[m_display].active_theme;
    WriteComment("Pixelmap ID definitions");
    CString out;
    BOOL gen_system_pixelmap_ids = FALSE;

    if (project_lib_version() < GX_VERSION_RESOURCE_ID_GENERATE_FIX)
    {
        gen_system_pixelmap_ids = TRUE;
    }

    res_info *info;
    int frame_id;
    CString upper;

    for (pixelmap_id = 1; pixelmap_id < m_pixelmap_dictionary.GetCount(); pixelmap_id++)
    {
        info = m_project->FindResource(m_display, active_theme, RES_TYPE_PIXELMAP, m_pixelmap_dictionary.GetAt(pixelmap_id));

        if (!info)
        {
            continue;
        }

        if (IsResEnabled(info) || IsSystemPixelmap(pixelmap_id))
        {
            for (frame_id = 0; frame_id < info->GetPixelmapFrameCount(); frame_id++)
            {
                if (!info->output_file_enabled || !info->binary_mode)
                {
                    // Generate pixlemap definitions for pixelmaps that are statically defined.
                    upper = MakePixelmapName(info, frame_id);
                    upper.MakeUpper();

                    if (info->is_default)
                    {
                        if ((m_display == 0) && gen_system_pixelmap_ids)
                        {
                            out.Format(_T("#define GX_PIXELMAP_ID_%s %d\n"), upper, output_pixelmap_id);
                            FileWrite(out);
                        }
                    }
                    else
                    {
                        if (m_num_displays > 1)
                        {
                            out.Format(_T("#define GX_PIXELMAP_ID_%s_%s %d\n"), UpperDisplayName(), upper, output_pixelmap_id);
                        }
                        else
                        {
                            out.Format(_T("#define GX_PIXELMAP_ID_%s %d\n"), upper, output_pixelmap_id);
                        }
                        FileWrite(out);
                    }
                    output_pixelmap_id++;
                }
            }
        }
    }

    out.Format(_T("#define %s_PIXELMAP_TABLE_SIZE %d\n"),
        UpperDisplayName(), m_pixelmap_table_size);
    FileWrite(out);
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WritePixelmapData(void)
{
    BOOL cpu_synergy = FALSE;
    res_info *info;
    CCommandInfo *pCmdInfo = GetCmdInfo();
    BOOL enabled;

    WriteComment("Pixelmap data definitions");

    for (int theme = 0; theme < m_project->mDisplays[m_display].num_themes; theme++)
    {
        m_ThemeName = m_project->mDisplays[m_display].themes[theme].theme_name;

        if (pCmdInfo->IsNoGui())
        {
            enabled = pCmdInfo->IsThemeEnabled(m_ThemeName);
        }
        else
        {
            enabled = m_project->mDisplays[m_display].themes[theme].gen_pixelmap_table;
        }

        if (!enabled) continue;

        for (int index = 1; index < m_pixelmap_dictionary.GetCount(); index++)
        {
            info = m_project->FindResource(m_display, theme, RES_TYPE_PIXELMAP, m_pixelmap_dictionary.GetAt(index));

            if (!info)
            {
                continue;
            }

            mPrivatePaletteWritten = FALSE;

            if (info->GetPixelmapFrameCount() && IsResEnabled(info) && (FindResourceReferenceTheme(info, theme) == -1))
            {
                for (int frame_id = 0; frame_id < info->GetPixelmapFrameCount(); frame_id++)
                {
                    m_map = info->GetPixelmap(frame_id);

                    if (!m_map)
                    {
                        continue;
                    }

                    if (info->output_file_enabled)
                    {
                        //Output pixelmap to the specified file
                        if (info->binary_mode)
                        {
                            if (!mp_bin_generater)
                            {
                                mp_bin_generater = new binary_resource_gen(m_project, BINARY_FILE_FORMAT_BIN_STANDALONE);
                                mp_bin_generater->SetDisplay(m_display);
                                mp_bin_generater->InitResource();
                            }

                            if (!mp_bin_generater->SetOutFile(info->output_file, info->binary_mode))
                            {
                                return;
                            }

                            mp_bin_generater->WritePixelmapBlock(info, 0, 0, theme, frame_id);
                            continue;
                        }
                        
                        if (!SetOutFile(info->output_file))
                        {
                            return;
                        }
                    }

                    if (info->raw)
                    {
                        // special case of raw format, just write it and return:
                        WriteRawPixelmap(info, frame_id);
                    }
                    else
                    {
                        if (IsRenesasDave2D(m_project))
                        {
                            // force convert the 16 bit with alpha formats to 32 bit argb for Dave2D
                            // this should be removed once we only allow compatible formats
                            if (m_map->gx_pixelmap_format == GX_COLOR_FORMAT_565RGB &&
                                (m_map->gx_pixelmap_flags & GX_PIXELMAP_ALPHA) &&
                                (info->output_color_format != GX_COLOR_FORMAT_32ARGB) &&
                                (info->output_color_format != GX_COLOR_FORMAT_4444ARGB) &&
                                (info->output_color_format != GX_COLOR_FORMAT_4444BGRA))
                            {
                                // If this is 16 bit pixelmap with alpha, convert to 32 bit argb format for Dave2D
                                info->output_color_format = GX_COLOR_FORMAT_32ARGB;
                            }
                        }

                        WritePixelmapData(info, theme, frame_id);
                    }

                    if (info->output_file_enabled)
                    {
                        m_outfile = outfile_list.GetAt(0);
                    }
                }
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WritePixelmapTable(void)
{
    res_info *info;
    CString out;
    CCommandInfo *pCmdInfo = GetCmdInfo();
    BOOL enabled;
    int pixelmap_id;
    int frame_id;
    CString name;

    WriteComment("Pixelmap Table");

    /* Extern pixelmaps that defined in custom output files. */
    for (int theme = 0; theme < m_project->mDisplays[m_display].num_themes; theme++)
    {
        m_ThemeName = m_project->mDisplays[m_display].themes[theme].theme_name;

        if (pCmdInfo->IsNoGui())
        {
            enabled = pCmdInfo->IsThemeEnabled(m_ThemeName);
        }
        else
        {
            enabled = m_project->mDisplays[m_display].themes[theme].gen_pixelmap_table;
        }

        if (!enabled) continue;

        for (pixelmap_id = 1; pixelmap_id < m_pixelmap_dictionary.GetCount(); pixelmap_id++)
        {
            info = m_project->FindResource(m_display, theme, RES_TYPE_PIXELMAP, m_pixelmap_dictionary.GetAt(pixelmap_id));

            if (IsResEnabled(info) && (info->output_file_enabled) && (!info->binary_mode))
            {
                CString theme_name = m_ThemeName;
                int reference_theme = FindResourceReferenceTheme(info, theme);
                if (reference_theme >= 0)
                {
                    theme_name = m_project->mDisplays[m_display].themes[reference_theme].theme_name;
                }

                for (frame_id = 0; frame_id < info->GetPixelmapFrameCount(); frame_id++)
                {
                    name = MakePixelmapName(info, frame_id);

                    out.Format(_T("extern GX_CONST GX_PIXELMAP %s_%s_%s_pixelmap;\n"), UpperDisplayName(), theme_name.MakeUpper(), name);
                    FileWrite(out);
                }
            }
        }
    }

    FileWrite(CString("\n"));

    /* Write pixelmap table. */
    for (int theme = 0; theme < m_project->mDisplays[m_display].num_themes; theme++)
    {
        m_ThemeName = m_project->mDisplays[m_display].themes[theme].theme_name;

        if (pCmdInfo->IsNoGui())
        {
            enabled = pCmdInfo->IsThemeEnabled(m_ThemeName);
        }
        else
        {
            enabled = m_project->mDisplays[m_display].themes[theme].gen_pixelmap_table;
        }

        if (!enabled) continue;


        CString name = m_project->mDisplays[m_display].name;
        name += "_";
        name += m_project->mDisplays[m_display].themes[theme].theme_name;
        out.Format(_T("GX_CONST GX_PIXELMAP *%s_pixelmap_table[] =\n{\n    GX_NULL"), name);
        FileWrite(out);

        for (pixelmap_id = 1; pixelmap_id < m_pixelmap_dictionary.GetCount(); pixelmap_id++)
        {
            info = m_project->FindResource(m_display, theme, RES_TYPE_PIXELMAP, m_pixelmap_dictionary.GetAt(pixelmap_id));

            if (IsResEnabled(info))
            {
                CString theme_name = m_ThemeName;
                int reference_theme = FindResourceReferenceTheme(info, theme);
                if (reference_theme >= 0)
                {
                    theme_name = m_project->mDisplays[m_display].themes[reference_theme].theme_name;
                }

                for (frame_id = 0; frame_id < info->GetPixelmapFrameCount(); frame_id++)
                {
                    name = MakePixelmapName(info, frame_id);

                    if (!info->output_file_enabled || !info->binary_mode)
                    {
                        out.Format(_T(",\n    &%s_%s_%s_pixelmap"), UpperDisplayName(), theme_name.MakeUpper(), name);
                        FileWrite(out);
                    }
                }
            }
            else if (IsSystemPixelmap(pixelmap_id))
            {
                out.Format(_T(",\n    GX_NULL"));
                FileWrite(out);
            }
        }

        out.Format(_T("\n};\n"));
        FileWrite(out);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteStringDefines(void)
{
    CString out;
    int string_id;
    string_table *pTable = m_project->mDisplays[m_display].stable;
    CString display_name = UpperDisplayName();
    display_name += "_";
    CArray<widget_info*>* info_list;
    widget_info* info;
    int reference_count;
    int output_id = 1;

    if (pTable && pTable->CountStrings() > 0)
    {
        WriteComment("String Ids");

        for (string_id = 1; string_id < pTable->CountStrings(); string_id++)
        {
            CString IdName = pTable->GetResourceIdName(string_id);

            if (IdName.IsEmpty())
            {
                continue;
            }

            info_list = pTable->GetMLViewReferenceWidgetInfoList(IdName);

            if (info_list)
            {
                reference_count = info_list->GetCount();
            }
            else
            {
                reference_count = 1;
            }

            info = NULL;

            for (int index = 0; index < reference_count; index++)
            {
                if (info_list)
                {
                    info = info_list->GetAt(index);

                    IdName = pTable->GetResourceIdName(string_id, info);
                }

                if (m_num_displays > 1)
                {
                    out.Format(_T("#define GX_STRING_ID_%s %d\n"), CString(display_name + IdName), output_id);
                }
                else
                {
                    out.Format(_T("#define GX_STRING_ID_%s %d\n"), CString(IdName), output_id);
                }

                output_id++;
                FileWrite(out);
            }
        }

        out.Format(_T("#define %s_STRING_TABLE_SIZE %d\n"),
            UpperDisplayName(), pTable->CountGeneratedStrings());
        FileWrite(out);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteStringData(void)
{
    CString out;
    int string_id = 1;
    int num_strings;
    int language = 0;
    CString LanguageName;
    CString display_name;

    string_table *pTable = m_project->mDisplays[m_display].stable;

    if (!pTable)
    {
        return;
    }

    num_strings = pTable->CountStrings();

    if (num_strings > 0)
    {
        WriteComment("String values");
        display_name = m_project->mDisplays[m_display].name;

        /* Pickup command info class instance. */
        CCommandInfo *pCmdInfo = GetCmdInfo();
        BOOL enabled;

        for (int language = 0; language < m_project->mHeader.num_languages; language++)
        {
            LanguageName = m_project->mHeader.languages[language].name;

            if (pCmdInfo->IsNoGui())
            {
                enabled = pCmdInfo->IsLanguageEnabled(LanguageName);
            }
            else
            {
                enabled = m_project->mDisplays[m_display].gen_string_table[language];
            }

            if (!enabled) continue;

            /* Include string data of enabled languages. */

            for (string_id = 1; string_id < num_strings; string_id++)
            {
                WriteOneStringData(display_name, language, string_id);
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
CString resource_gen::RichTextResIdName2ResId(studiox_project* project, int display, CString &val)
{
    CString out("");
    CString tag;
    CString id_name;
    CString id_prefix;
    CString id_val_string;
    int res_type;
    int res_id;
    int index = 0;

    while (1)
    {
        // Find tag start flag
        index = val.Find('<');

        if (index >= 0)
        {
            out.Append(val.Left(index + 1));
            val = val.Mid(index + 1);

            index = val.Find(_T(" "));

            if (index >= 0)
            {
                // Get tag
                tag = val.Left(index);

                if (tag == "f")
                {
                    res_type = RES_TYPE_FONT;
                    id_prefix = "GX_FONT_ID_";
                }
                else if ((tag == "c") || (tag == "hc"))
                {
                    res_type = RES_TYPE_COLOR;
                    id_prefix = "GX_COLOR_ID_";
                }
                else
                {
                    continue;
                }

                out.Append(val.Left(index + 1));
                val = val.Mid(index + 1);

                index = val.Find(_T(">"));
                if (index >= 0)
                {
                    // Get resource id name
                    id_name = val.Left(index);

                    if (id_name.Find(id_prefix) == 0)
                    {
                        id_name = id_name.Mid(id_prefix.GetLength());
                        res_id = project->GetResourceId(display, res_type, id_name);

                        if (res_id)
                        {
                            val = val.Mid(index + 1);
                            id_val_string.Format(_T("%d>"), res_id);
                            out += id_val_string;
                        }
                    }
                }
            }
        }
        else
        {
            out.Append(val);
            break;
        }
    }

    return out;
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::MakeUtf8String(studiox_project* project, CString val, int language_index, GX_STRING *out_string, int display, BOOL gen, widget_info *info)
{
    val = RichTextResIdName2ResId(project, display, val);

    // The maximun UTF8 character is 6 bytes, calculate the maximun utf8 buffer size needed for the string.
    int max_length = val.GetLength() * 6 + 1;
    GX_STRING string;
    GX_STRING normalized_text;

    string.gx_string_ptr = new char[max_length];
    strcpy_s((char *)string.gx_string_ptr, max_length, CT2A(val.GetString(), CP_UTF8));
    string.gx_string_length = strnlen_s(string.gx_string_ptr, max_length);

    if (gx_studio_canonical_normalize((GX_CONST GX_STRING *)&string, &normalized_text) == GX_SUCCESS)
    {
        delete string.gx_string_ptr;

        string = normalized_text;
    }

    if (project->mHeader.languages[language_index].support_bidi_text &&
        project->mHeader.languages[language_index].gen_reordered_bidi_text && gen)
    {
        GX_STRING reordered_bidi_text;

        MakeReorderedBidiText(&string, &reordered_bidi_text, display, info);

        delete string.gx_string_ptr;
        string = reordered_bidi_text;
    }

    if (project->mHeader.languages[language_index].support_thai_glyph_shaping &&
        (!gen || project->mHeader.languages[language_index].gen_adjusted_thai_string))
    {

        GX_STRING adjusted_thai_string;
        MakeAdjustedThaiString(&string, &adjusted_thai_string);

        if (adjusted_thai_string.gx_string_ptr)
        {
            delete string.gx_string_ptr;
            string = adjusted_thai_string;
        }
    }

    *out_string = string;
}

////////////////////////////////////////////////////////////////////////////////////////////////
bool resource_gen::GetMlTextDisplayInfo(widget_info *info, int* font_id, GX_VALUE* display_width)
{
    if (info && (info->basetype == GX_TYPE_MULTI_LINE_TEXT_VIEW))
    {
        // Calculate display width
        GX_WIDGET widget;
        GX_RECTANGLE client;
        INT width;

        widget.gx_widget_style = info->style;
        widget.gx_widget_size = info->size;
        gx_widget_client_get(&widget, -1, &client);

        width = client.gx_rectangle_right - client.gx_rectangle_left + 1;
        width = width - (info->ewi.text_info.whitespace << 1) - 3;

        // Retrieve font
        *font_id = info->font_id[NORMAL_FONT_INDEX];

        widget_info *child = info->GetChildWidgetInfo();

        while (child)
        {
            if (child->basetype == GX_TYPE_VERTICAL_SCROLL)
            {
                width -= (child->size.gx_rectangle_right - child->size.gx_rectangle_left + 1);
                break;
            }

            child = child->GetNextWidgetInfo();
        }

        *display_width = (GX_VALUE)width;
        return TRUE;
    }

    return FALSE;
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::MakeReorderedBidiText(GX_STRING *utf8str, GX_STRING *out_string, int display, widget_info *info)
{
    //generate bidi text in display order
    GX_BIDI_TEXT_INFO input_info;
    GX_BIDI_RESOLVED_TEXT_INFO *resolved_info;
    char *reordered_bidi_text = GX_NULL;
    UINT  reordered_index = 0;
    GX_VALUE display_width;
    int font_id;

    memset(&input_info, 0, sizeof(GX_BIDI_TEXT_INFO));

    if (GetMlTextDisplayInfo(info, &font_id, &display_width))
    {
        studiox_project* project = GetOpenProject();
        res_info* info = project->FindResource(display, 0, RES_TYPE_FONT, font_id);

        if (info)
        {
            input_info.gx_bidi_text_info_display_width = display_width;
            input_info.gx_bidi_text_info_font = info->font;
        }
    }

    input_info.gx_bidi_text_info_text = *utf8str;

    if (_gx_utility_bidi_paragraph_reorder(&input_info, &resolved_info) == GX_SUCCESS)
    {
        int buffer_size = 0;
        UINT index;
        GX_BIDI_RESOLVED_TEXT_INFO* next = resolved_info;
        GX_STRING* line_string;

        // Calculate buffer size needed for loading the reordered bidi text.
        while (next)
        {
            for (index = 0; index < next->gx_bidi_resolved_text_info_total_lines; index++)
            {
                if (next->gx_bidi_resolved_text_info_text)
                {
                    buffer_size += next->gx_bidi_resolved_text_info_text[index].gx_string_length;
                }

                buffer_size++;
            }
            next = next->gx_bidi_resolved_text_info_next;
        }

        buffer_size++;
        reordered_bidi_text = new char[buffer_size];

        next = resolved_info;

        GX_BOOL insert_line_break = GX_FALSE;

        // Copy reordered bidi text to the buffer.
        while (next)
        {
            for (index = 0; index < next->gx_bidi_resolved_text_info_total_lines; index++)
            {
                if (next->gx_bidi_resolved_text_info_text)
                {
                    line_string = &next->gx_bidi_resolved_text_info_text[index];
                    memcpy_s(reordered_bidi_text + reordered_index, buffer_size - reordered_index, line_string->gx_string_ptr, line_string->gx_string_length);
                    reordered_index += line_string->gx_string_length;
                }

                if ((index < next->gx_bidi_resolved_text_info_total_lines - 1) ||
                    (next->gx_bidi_resolved_text_info_next))
                {
                    reordered_bidi_text[reordered_index++] = GX_KEY_CARRIAGE_RETURN;
                }
            }
            next = next->gx_bidi_resolved_text_info_next;
        }

        reordered_bidi_text[reordered_index] = '\0';

        _gx_utility_bidi_resolved_text_info_delete(&resolved_info);
    }

    out_string->gx_string_ptr = reordered_bidi_text;
    out_string->gx_string_length = reordered_index;
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::MakeAdjustedThaiString(GX_STRING *utf8str, GX_STRING *out_string)
{
    ULONG *code_list;
    UINT code_count;
    UINT index;
    GX_CHAR *adjusted_string;
    UINT     count;
    UINT     glyph_len;

    out_string->gx_string_ptr = GX_NULL;
    out_string->gx_string_length = 0;

    if (_gx_utility_thai_glyph_shaping(utf8str, &code_list, &code_count) == GX_SUCCESS)
    {
        adjusted_string = new GX_CHAR[code_count * 6 + 1];
        count = 0;

        for (index = 0; index < code_count; index++)
        {
            _gx_utility_unicode_to_utf8(code_list[index], (GX_UBYTE *)(adjusted_string + count), &glyph_len);
            count += glyph_len;
        }

        _gx_system_memory_free(code_list);
        adjusted_string[count] = '\0';
        
        out_string->gx_string_ptr = adjusted_string;
        out_string->gx_string_length = count;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteOneStringData(CString &display_name, int language_index, int string_id)
{
    CString out;
    GX_STRING utf8str;
    GX_CONST GX_CHAR *data;
    unsigned char  byte;
    BOOL  HasMultiByte = FALSE;

    string_table* pTable = m_project->mDisplays[m_display].stable;

    CString id_name = pTable->GetResourceIdName(string_id);

    if (id_name.IsEmpty())
    {
        return;
    }
    CString val = pTable->GetString(id_name, language_index);

    if (val.IsEmpty())
    {
        return;
    }

    CArray<widget_info*> *info_list = pTable->GetMLViewReferenceWidgetInfoList(id_name);

    int reference_count = 1;

    if (info_list)
    {
        reference_count = info_list->GetCount();
    }

    widget_info *info = NULL;

    for (int index = 0; index < reference_count; index++)
    {
        if (info_list)
        {
            info = info_list->GetAt(index);
            id_name = pTable->GetResourceIdName(string_id, info);
        }

        MakeUtf8String(m_project, val, language_index, &utf8str, m_display, TRUE, info);

        data = utf8str.gx_string_ptr;

        while (*data)
        {
            byte = *data++;
            if (byte & 0x80)
            {
                HasMultiByte = TRUE;
                break;
            }
        }

        CString language_name = m_project->mHeader.languages[language_index].name;
        language_name.Replace(' ', '_');

        if (HasMultiByte)
        {
            out.Format(_T("GX_CONST GX_UBYTE %s_%s_%s[] = {"), display_name, id_name, language_name);
            FileWrite(out);

            data = utf8str.gx_string_ptr;

            while (*data)
            {
                byte = *data++;
                out.Format(_T("0x%02x, "), byte);
                FileWrite(out);
            }
            FileWrite(CString("0x00};\n"));
        }
        else
        {
            val = utf8str.gx_string_ptr;
            val.Replace(_T("\\"), _T("\\\\"));
            val.Replace(_T("\""), _T("\\\""));
            val.Replace(_T("\'"), _T("\\\'"));
            val.Replace(_T("\n"), _T("\\n"));
            val.Replace(_T("\r"), _T("\\r"));

            out.Format(_T("GX_CONST GX_UBYTE %s_%s_%s[] = \"%s\";\n"), display_name, id_name, language_name, val);

            FileWrite(out);
        }

        delete utf8str.gx_string_ptr;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteStringTable(void)
{
    CString out;
    int string_id = 1;
    int num_strings;
    int language = 0;
    CString LanguageName;
    CString display_name;
    CString val;

    string_table *pTable = m_project->mDisplays[m_display].stable;

    if (!pTable)
    {
        return;
    }

    num_strings = pTable->CountStrings();

    if (num_strings > 0)
    {
        display_name = m_project->mDisplays[m_display].name;

        /* Pickup command info class instance. */
        CCommandInfo *pCmdInfo = GetCmdInfo();
        BOOL enabled;
        INT language_count = 0;

        for (int language = 0; language < m_project->mHeader.num_languages; language++)
        {
            LanguageName = m_project->mHeader.languages[language].name;

            if (pCmdInfo->IsNoGui())
            {
                enabled = pCmdInfo->IsLanguageEnabled(LanguageName);
            }
            else
            {
                enabled = m_project->mDisplays[m_display].gen_string_table[language];
            }

            if (!enabled) continue;

            out.Format(_T("\n/* String Table for %s language %s */\n\n"), display_name, LanguageName);
            FileWrite(out);

            LanguageName.Replace(' ', '_');
            if(project_lib_version() >= GX_VERSION_STRING_LENGTH_FIX)
            {
                WriteOneStringTableExt(display_name, LanguageName, language, pTable, num_strings);
            }
            else
            {
                WriteOneStringTable(display_name, LanguageName, language, pTable, num_strings);
            }

            /* Output string table of enabled languages. */

            language_count++;
        }

        // now write the language table
  
        WriteComment(" Language Table ");

        if (language_count)
        {
            if (project_lib_version() >= GX_VERSION_STRING_LENGTH_FIX)
            {
                WriteLanguageTableExt(display_name, language_count);
            }
            else
            {
                WriteLanguageTable(display_name, language_count);
            }

            if (string_table::TestGenerateLanguageDirectionTable())
            {
                WriteComment(" Language Direction Table ");

                WriteLanguageDirectionTable(display_name, language_count);
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteLanguageTable(CString display_name, INT language_count)
{
    CString out;
    CString LanguageName;
    CCommandInfo* pCmdInfo = GetCmdInfo();
    BOOL enabled;

    out.Format(_T("\nGX_CONST GX_UBYTE **%s_language_table[%d] = \n{\n"), m_project->mDisplays[m_display].name, language_count);

    FileWrite(out);

    for (int language = 0; language < m_project->mHeader.num_languages; language++)
    {
        LanguageName = m_project->mHeader.languages[language].name;

        if (pCmdInfo->IsNoGui())
        {
            enabled = pCmdInfo->IsLanguageEnabled(LanguageName);
        }
        else
        {
            enabled = m_project->mDisplays[m_display].gen_string_table[language];
        }

        if (!enabled) continue;

        /* Output language table with enabled string tables. */
        LanguageName.Replace(' ', '_');
        out.Format(_T("    %s_%s_string_table,\n"), display_name, LanguageName);

        FileWrite(out);
    }
    FileWrite(CString("};\n"));
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteLanguageTableExt(CString display_name, INT language_count)
{
    CString out;
    CString LanguageName;
    CCommandInfo* pCmdInfo = GetCmdInfo();
    BOOL enabled;

    out.Format(_T("\nGX_CONST GX_STRING *%s_language_table[%d] = \n{\n"), m_project->mDisplays[m_display].name, language_count);

    FileWrite(out);

    for (int language = 0; language < m_project->mHeader.num_languages; language++)
    {
        LanguageName = m_project->mHeader.languages[language].name;

        if (pCmdInfo->IsNoGui())
        {
            enabled = pCmdInfo->IsLanguageEnabled(LanguageName);
        }
        else
        {
            enabled = m_project->mDisplays[m_display].gen_string_table[language];
        }

        if (!enabled) continue;

        /* Output language table with enabled string tables. */
        LanguageName.Replace(' ', '_');
        out.Format(_T("    %s_%s_string_table,\n"), display_name, LanguageName);

        FileWrite(out);
    }
    FileWrite(CString("};\n"));
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteLanguageDirectionTable(CString display_name, INT language_count)
{
    CString out;

    out.Format(_T("\nGX_CONST GX_UBYTE %s_language_direction_table[%d] = \n{\n"), m_project->mDisplays[m_display].name, language_count);

    FileWrite(out);

    for (int language = 0; language < m_project->mHeader.num_languages; language++)
    {
        if (string_table::IsRight2LeftLanguage(language))
        {
            out = L"    GX_LANGUAGE_DIRECTION_RTL";
        }
        else
        {
            out = L"    GX_LANGUAGE_DIRECTION_LTR";
        }

        FileWrite(out);

        if (language == m_project->mHeader.num_languages - 1)
        {
            out = L"\n";
        }
        else
        {
            out = L",\n";
        }

        FileWrite(out);
    }
    FileWrite(CString("};\n"));
}


////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteOneStringTable(CString &display_name, CString &language_name, int language_index,
                                       string_table* string_table, int num_strings)
{
        CString out;
        CString val;
        int string_id;
        CString id_name;

        out.Format(_T("GX_CONST GX_UBYTE *%s_%s_string_table[%d] =\n{\n    GX_NULL,\n"),
            display_name, language_name, num_strings);
        FileWrite(out);
 
        for (string_id = 1; string_id < num_strings; string_id++)
        {
            id_name = string_table->GetResourceIdName(string_id);

            if (id_name.IsEmpty())
            {   
                continue;
            }


            val = string_table->GetString(id_name, language_index);

            if (val.IsEmpty())
            {
                if (string_id < num_strings - 1)
                {
                    out.Format(_T("    GX_NULL,\n"));
                }
                else
                {
                    out.Format(_T("    GX_NULL\n"));
                }
            }
            else
            {
                if (string_id < num_strings - 1)
                {
                    out.Format(_T("    %s_%s_%s,\n"), display_name, id_name, language_name);
                }
                else
                {
                    out.Format(_T("    %s_%s_%s\n"), display_name, id_name, language_name);
                }
            }
            FileWrite(out);
        }
        out.Format(_T("\n};\n"));
        FileWrite(out);
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteOneStringTableExt(CString &display_name, CString &language_name, int language_index,
                                                       string_table* string_table, int num_strings)
{
    CString out;
    CString val;
    int string_id;
    CString id_name;

    out.Format(_T("GX_CONST GX_STRING %s_%s_string_table[%d] =\n{\n    {GX_NULL, 0},\n"),
        display_name, language_name, string_table->CountGeneratedStrings());
    FileWrite(out);

    CArray<widget_info *> *info_list;
    int reference_count;
    widget_info *info;

    for (string_id = 1; string_id < num_strings; string_id++)
    {
        id_name = string_table->GetResourceIdName(string_id);

        if (id_name.IsEmpty())
        {
            continue;
        }

        val = string_table->GetString(id_name, language_index);

        info_list = string_table->GetMLViewReferenceWidgetInfoList(id_name);
        info = NULL;
        reference_count = 1;

        if (info_list)
        {
            reference_count = info_list->GetCount();
        }

        for (int index = 0; index < reference_count; index++)
        {

            if (info_list)
            {
                info = info_list->GetAt(index);
                id_name = string_table->GetResourceIdName(string_id, info);
            }

            if (val.IsEmpty())
            {
                if (string_id < num_strings - 1)
                {
                    out.Format(_T("    {GX_NULL, 0},\n"));
                }
                else
                {
                    out.Format(_T("    {GX_NULL, 0}\n"));
                }
            }
            else
            {

                if (string_id < num_strings - 1)
                {
                    out.Format(_T("    {(GX_CONST GX_CHAR *)%s_%s_%s, sizeof(%s_%s_%s) - 1},\n"),
                        display_name, id_name, language_name,
                        display_name, id_name, language_name);
                }
                else
                {
                    out.Format(_T("    {(GX_CONST GX_CHAR *)%s_%s_%s, sizeof(%s_%s_%s) - 1}\n"),
                        display_name, id_name, language_name,
                        display_name, id_name, language_name);
                }
            }
            FileWrite(out);
        }
    }
    out.Format(_T("};\n"));
    FileWrite(out);
}

void resource_gen::WriteScrollbarAppearance(GX_SCROLLBAR_APPEARANCE &appear)
{
    CString out;

    if (project_lib_version() >= 50302)
    {
        out.Format(_T("")
            _T("    {\n")
            _T("        %d, /* scroll width */\n")
            _T("        %d, /* thumb width  */\n")
            _T("        %d, /* thumb travel min */\n")
            _T("        %d, /* thumb travel max */\n")
            _T("        %d, /* thumb border style */\n")
            _T("        %s, /* scroll fill pixelmap */\n")
            _T("        %s, /* scroll thumb pixelmap */\n")
            _T("        %s, /* scroll up pixelmap */\n")
            _T("        %s, /* scroll down pixelmap */\n")
            _T("        %s, /* scroll thumb color */\n")
            _T("        %s, /* scroll thumb border color */\n")
            _T("        %s, /* scroll button color */\n")
            _T("    },\n"),
            appear.gx_scroll_width,
            appear.gx_scroll_thumb_width, 
            appear.gx_scroll_thumb_travel_min,
            appear.gx_scroll_thumb_travel_max,
            appear.gx_scroll_thumb_border_style,
            screen_generator::GetPixelmapIdName(m_project, m_display, appear.gx_scroll_fill_pixelmap),
            screen_generator::GetPixelmapIdName(m_project, m_display, appear.gx_scroll_thumb_pixelmap),
            screen_generator::GetPixelmapIdName(m_project, m_display, appear.gx_scroll_up_pixelmap),
            screen_generator::GetPixelmapIdName(m_project, m_display, appear.gx_scroll_down_pixelmap),
            screen_generator::GetColorIdName(m_project, m_display, appear.gx_scroll_thumb_color),
            screen_generator::GetColorIdName(m_project, m_display, appear.gx_scroll_thumb_border_color),
            screen_generator::GetColorIdName(m_project, m_display, appear.gx_scroll_button_color));
    }
    else
    {
        out.Format(_T("")
            _T("    {\n")
            _T("        %d, /* scroll width */\n")
            _T("        %d, /* thumb width  */\n")
            _T("        %d, /* thumb travel min */\n")
            _T("        %d, /* thumb travel max */\n")
            _T("        %s, /* scroll fill pixelmap */\n")
            _T("        %s, /* scroll thumb pixelmap */\n")
            _T("        %s, /* scroll up pixelmap */\n")
            _T("        %s, /* scroll down pixelmap */\n")
            _T("        %s, /* scroll fill color */\n")
            _T("        %s, /* scroll button color */\n")
            _T("    },\n"),
            appear.gx_scroll_width,
            appear.gx_scroll_thumb_width, 
            appear.gx_scroll_thumb_travel_min,
            appear.gx_scroll_thumb_travel_max,
            screen_generator::GetPixelmapIdName(m_project, m_display, appear.gx_scroll_fill_pixelmap),
            screen_generator::GetPixelmapIdName(m_project, m_display, appear.gx_scroll_thumb_pixelmap),
            screen_generator::GetPixelmapIdName(m_project, m_display, appear.gx_scroll_up_pixelmap),
            screen_generator::GetPixelmapIdName(m_project, m_display, appear.gx_scroll_down_pixelmap),
            _T("GX_COLOR_ID_SCROLL_FILL"),
            screen_generator::GetColorIdName(m_project, m_display, appear.gx_scroll_button_color));
    }
    FileWrite(out);
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteThemes(void)
{

    int theme;
    int theme_count = 0;
    CString out;
    CString name;
    BOOL  enabled;
    CString color_table_name("GX_NULL");
    CString font_table_name("GX_NULL");
    CString pixelmap_table_name("GX_NULL");

    CCommandInfo *pCmdInfo = GetCmdInfo();
   
    for (theme = 0; theme < m_project->mDisplays[m_display].num_themes; theme++)
    {
        if (pCmdInfo->IsNoGui())
        {
            enabled = pCmdInfo->IsThemeEnabled(m_project->mDisplays[m_display].themes[theme].theme_name);
        }
        else
        {
            enabled = m_project->mDisplays[m_display].themes[theme].enabled;
        }

        if (!enabled) continue;

        theme_count++;

        name = m_project->mDisplays[m_display].name;
        name += "_";
        name += m_project->mDisplays[m_display].themes[theme].theme_name;

        if (m_project->mDisplays[m_display].themes[theme].gen_color_table || pCmdInfo->IsNoGui())
        {
            color_table_name.Format(_T("%s_color_table"), name);
        }

        if (m_project->mDisplays[m_display].themes[theme].gen_font_table || pCmdInfo->IsNoGui())
        {
            font_table_name.Format(_T("%s_font_table"), name);
        }

        if (m_project->mDisplays[m_display].themes[theme].gen_pixelmap_table || pCmdInfo->IsNoGui())
        {
            pixelmap_table_name.Format(_T("%s_pixelmap_table"), name);
        }

        out.Format(_T("\nGX_THEME %s =\n")
            _T("{\n")
            _T("    (GX_COLOR *) %s,\n")
            _T("    (GX_FONT **) %s,\n")
            _T("    (GX_PIXELMAP **) %s,\n"),
            name, color_table_name, font_table_name, pixelmap_table_name);
        FileWrite(out);

        if (m_project->mDisplays[m_display].colorformat == GX_COLOR_FORMAT_8BIT_PALETTE &&
            m_project->mDisplays[m_display].themes[theme].palette != NULL)
        {
            out.Format(_T("    (GX_COLOR *) %s_palette,\n"), name);
        }
        else
        {
            out.Format(_T("    NULL,\n"));
        }
        FileWrite(out);

        WriteScrollbarAppearance(m_project->mDisplays[m_display].themes[theme].VScrollAppearance);
        WriteScrollbarAppearance(m_project->mDisplays[m_display].themes[theme].HScrollAppearance);
        out.Empty();
        screen_generator::AddScrollbarStyles(m_project->mDisplays[m_display].themes[theme].VScrollStyle, out);
        out.TrimLeft('|');
        out = CString(_T("    ")) + out + _T(",\n");
        FileWrite(out);

        out.Empty();
        screen_generator::AddScrollbarStyles(m_project->mDisplays[m_display].themes[theme].HScrollStyle, out);
        out.TrimLeft('|');
        out = CString(_T("    ")) + out + _T(",\n");
        FileWrite(out);
        out.Format(_T("    %d, /* color table size */\n"), m_color_table_size);
        FileWrite(out);
        out.Format(_T("    %d, /* font table size */\n"), m_font_table_size);
        FileWrite(out);
        out.Format(_T("    %d, /* pixelmap table size */\n"), m_pixelmap_table_size);
        FileWrite(out);
        if (m_project->mDisplays[m_display].colorformat == GX_COLOR_FORMAT_8BIT_PALETTE &&
            m_project->mDisplays[m_display].themes[theme].palette != NULL)
        {
            /* Only 8bit palette size is wanted to be generated. 
               4bpp driver contains palette table. But it is just used inside Studio.*/
            out.Format(_T("    %d  /* palette size */\n"), m_project->mDisplays[m_display].themes[theme].palette_total_size);
        
        }
        else
        {
            out.Format(_T("    %d  /* palette size */\n"), 0);
        }
        FileWrite(out);
        FileWrite(CString("\n};\n"));
    }

    if (theme_count)
    {
        out.Format(_T("GX_CONST GX_THEME *%s_theme_table[%d] =\n{\n"),
            m_project->mDisplays[m_display].name,
            theme_count);
        FileWrite(out);
        INT count = 0;

        for (theme = 0; theme < m_project->mDisplays[m_display].num_themes; theme++)
        {
            if (pCmdInfo->IsNoGui())
            {
                enabled = pCmdInfo->IsThemeEnabled(m_project->mDisplays[m_display].themes[theme].theme_name);
            }
            else
            {
                enabled = m_project->mDisplays[m_display].themes[theme].enabled;
            }

            if (!enabled) continue;

            count++;

            name = m_project->mDisplays[m_display].name;
            name += "_";
            name += m_project->mDisplays[m_display].themes[theme].theme_name;
            if (count < theme_count)
            {
                out.Format(_T("    &%s,\n"), name);
            }
            else
            {
                out.Format(_T("    &%s\n"), name);
            }
            FileWrite(out);
        }
        FileWrite(CString("};\n\n"));
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
GX_FONT *resource_gen::GetPageHead(res_info* info, int theme_id, int font_id)
{
    GX_FONT* head_page = NULL;

    if (!info->pathinfo.pathname.IsEmpty())
    {
        head_page = m_optimized_fonts[theme_id].GetAt(font_id);

        if (!head_page)
        {
            /* KGM Make the font again, with optimization, and write out the optimized version */
            /* Don't forget to delete the temporary font */

            head_page = MakeOptimizedFont(info, m_display, m_warn_on_error);

            if (head_page)
            {
                m_optimized_fonts[theme_id].SetAt(font_id, head_page);
            }
            else
            {
                // Only generate error once.
                m_warn_on_error = FALSE;
            }
        }
    }
    else
    {
        // Rotation angle is set, need to rotate default system font.
        switch (info->font_bits)
        {
        case 8:
            head_page = &_gx_system_font_8bpp;
            break;

        case 4:
            if (IsDave2dFontFormat(m_project, m_display))
            {
                head_page = &_gx_dave2d_system_font_4bpp;
            }
            else
            {
                head_page = &_gx_system_font_4bpp;
            }
            break;

        case 1:
            if (IsDave2dFontFormat(m_project, m_display))
            {
                head_page = &_gx_dave2d_system_font_mono;
            }
            else
            {
                head_page = &_gx_system_font_mono;
            }
            break;

        default:
            // Do nothing.
            break;
        }
    }

    return head_page;
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteFont(res_info *info, int theme_id, int font_id)
{
    int pagecount = 1;
    int pageindex;
    GX_FONT *head_page = GetPageHead(info, theme_id, font_id);
    BOOL IsLast = TRUE;

    if (!head_page)
    {
        CString msg;
        msg.Format(_T("Unable to create font: %s using pathname: %s"), info->name, info->pathinfo.pathname);
        ErrorMsg(msg);
        return;
    }

    // write the pages out in reverse order, so that we can link them together without
    // first declaring them.

    const GX_FONT *font_page = head_page;

    while(font_page->gx_font_next_page)
    {
        font_page = font_page->gx_font_next_page;
        pagecount++;
    }

    CString name;

    while(pagecount)
    {
        font_page = head_page;
        for (pageindex = 1; pageindex < pagecount; pageindex++)
        {
            font_page = font_page->gx_font_next_page;
        }

        name.Format(_T("%s_%s"), m_ThemeName.MakeUpper(), info->name);

        WriteFontPage(font_page, name, pagecount, IsLast, info->output_file_enabled);
        pagecount--;
        IsLast = FALSE;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteKerningTable(GX_UBYTE *kerning_table, CString &name, GX_CHAR_CODE charval)
{
    GX_UBYTE *data;
    CString out;
    CString val;
    BOOL written = TRUE;
    int table_size;
    GX_UBYTE pair_counts = *kerning_table;

    /* Add pair counts and kerning value size. */
    table_size = sizeof(GX_UBYTE) + pair_counts * (sizeof(GX_CHAR) + sizeof(GX_UBYTE));

    /* Write kerning table */
    out.Format(_T("static GX_CONST GX_UBYTE FONT_%s_char_%2x_kerning_table[%u] =\n{\n"), name, charval, table_size);
    FileWrite(out);
    out = CString("    ");

    data = kerning_table;
    for (int i = 0; i < table_size; i++)
    {
        val.Format(_T("0x%02x"), *data);
        out += val;
        if (i != (table_size - 1))
        {
            out += ", ";
        }
        written = CheckLineFeed(out);
        data++;
    }
    if (!written)
    {
        FileWrite(out);
    }
    out = CString("\n};\n");
    FileWrite(out);
}

////////////////////////////////////////////////////////////////////////////////////////////////
GX_UBYTE *resource_gen::Rotate8bitGlyphData(GX_CONST GX_UBYTE* map, INT width, INT height)
{
    int rotated_width = height;
    int rotated_height = width;
    int data_size = rotated_width * rotated_height;
    int putsign;

    if (!data_size)
    {
        return NULL;
    }

    GX_UBYTE* data = new GX_UBYTE[data_size];
    GX_UBYTE* putrow = data;
    GX_UBYTE* put;
    GX_CONST GX_UBYTE* get = map;

    if (m_project->mDisplays[m_display].rotation_angle == GX_SCREEN_ROTATION_CW)
    {
        /* Write row from top to bottom to colum from left to right. */
        putrow += (rotated_height - 1) * rotated_width;
        putsign = 1;
    }
    else
    {
        // CCW
        putrow += (rotated_width - 1);
        putsign = -1;
    }

    for (int h = 0; h < height; h++)
    {
        put = putrow;

        for (int w = 0; w < width; w++)
        {
            *put = *get;
            get++;
            put -= rotated_width * putsign;
        }

        putrow += putsign;
    }

    return data;
}

////////////////////////////////////////////////////////////////////////////////////////////////
GX_UBYTE* resource_gen::Rotate4bitGlyphData(GX_CONST GX_UBYTE* map, INT width, INT height)
{
    int datasize;
    int rotated_width = height;
    int rotated_height = width;
    GX_UBYTE* data;
    GX_UBYTE* putrow;
    GX_UBYTE* put;
    int       putstride;
    int       putsign;
    GX_CONST GX_UBYTE* getrow;
    GX_CONST GX_UBYTE* get;
    int                getstride;
    GX_UBYTE pixel;

    putstride = GetRowPitch(rotated_width, 4);
    datasize = putstride * rotated_height;
    data = new GX_UBYTE[datasize];
    putrow = data;

    getstride = GetRowPitch(width, 4);
    getrow = map;

    if (m_project->mDisplays[m_display].rotation_angle == GX_SCREEN_ROTATION_CW)
    {
        /* Write row from top to bottom to colum from left to right. */
        putrow += (rotated_height - 1) * putstride;
        putsign = 1;
    }
    else
    {
        getrow += (height - 1) * getstride;
        putsign = -1;
    }

    for (int h = 0; h < height; h++)
    {
        put = putrow;
        get = getrow;

        for (int w = 0; w < width; w++)
        {
            if (w & 1)
            {
                if (IsDave2dFontFormat(m_project, m_display))
                {
                    pixel = (*get) & 0xf0;
                }
                else
                {
                    pixel = ((*get) << 4);
                }

                get++;
            }
            else
            {
                if (IsDave2dFontFormat(m_project, m_display))
                {
                    pixel = ((*get) << 4);
                }
                else
                {
                    pixel = (*get) & 0xf0;
                }
            }

            if (h & 1)
            {
                if (IsDave2dFontFormat(m_project, m_display))
                {
                    *put |= pixel;
                }
                else
                {
                    *put |= (pixel >> 4);
                }
            }
            else
            {
                if (IsDave2dFontFormat(m_project, m_display))
                {
                    *put = (pixel >> 4);
                }
                else
                {
                    *put = pixel;
                }
            }

            put -= putstride * putsign;
        }

        getrow += getstride * putsign;

        if (h & 1)
        {
            putrow++;
        }
    }

    return data;
}

////////////////////////////////////////////////////////////////////////////////////////////////
GX_UBYTE* resource_gen::Rotate1bitGlyphData(GX_CONST GX_UBYTE* map, INT width, INT height)
{
    int datasize;
    int rotated_width = height;
    int rotated_height = width;
    GX_UBYTE* data;
    GX_UBYTE* putrow;
    GX_UBYTE* put;
    int       putstride;
    int       putsign;
    GX_UBYTE  putmask;
    GX_CONST GX_UBYTE* getrow;
    GX_CONST GX_UBYTE* get;
    int                getstride;
    GX_UBYTE           getmask;
    GX_UBYTE pixel;

    putstride = GetRowPitch(rotated_width, 1);
    datasize = putstride * rotated_height;
    data = new GX_UBYTE[datasize];
    memset(data, 0, datasize);
    putrow = data;

    getstride = GetRowPitch(width, 1);
    getrow = map;

    if (m_project->mDisplays[m_display].rotation_angle == GX_SCREEN_ROTATION_CW)
    {
        putrow += (rotated_height - 1) * putstride;
        putsign = 1;
    }
    else
    {
        // CCW
        getrow += (height - 1) * getstride;
        putsign = -1;
    }

    if (IsDave2dFontFormat(m_project, m_display))
    {
        putmask = 0x01;

        /* Write row from top to bottom to colum from left to right. */
        for (int h = 0; h < height; h++)
        {
            put = putrow;
            get = getrow;

            getmask = 0x01;

            for (int w = 0; w < width; w++)
            {
                pixel = *get;

                if (pixel & getmask)
                {
                    *put |= putmask;
                }

                if (getmask == 0x80)
                {
                    getmask = 0x01;
                    get++;
                }
                else
                {
                    getmask <<= 1;
                }

                put -= putstride * putsign;
            }

            getrow += getstride * putsign;

            if (putmask == 0x80)
            {
                putmask = 0x01;
                putrow++;
            }
            else
            {
                putmask <<= 1;
            }
        }
    }
    else
    {
        putmask = 0x80;

        /* Write row from top to bottom to colum from left to right. */
        for (int h = 0; h < height; h++)
        {
            put = putrow;
            get = getrow;

            getmask = 0x80;

            for (int w = 0; w < width; w++)
            {
                pixel = *get;

                if (pixel & getmask)
                {
                    *put |= putmask;
                }

                if (getmask == 0x01)
                {
                    getmask = 0x80;
                    get++;
                }
                else
                {
                    getmask >>= 1;
                }

                put -= putstride * putsign;
            }

            getrow += getstride * putsign;

            if (putmask == 0x01)
            {
                putmask = 0x80;
                putrow++;
            }
            else
            {
                putmask >>= 1;
            }
        }
    }

    return data;
}

////////////////////////////////////////////////////////////////////////////////////////////////
VOID resource_gen::RotateGlyphData(GX_CONST GX_GLYPH* glyph, GX_UBYTE font_format, GX_UBYTE** rotated_map, INT* rotated_map_size)
{
    GX_UBYTE* rotated_data = GX_NULL;
    GX_UBYTE* decoded_data = GX_NULL;
    GX_CONST GX_UBYTE* input_data;

    if ((font_format & GX_FONT_FORMAT_COMPRESSED) &&
        (((GX_COMPRESSED_GLYPH*)glyph)->gx_glyph_map_size & 0x8000))
    {
        decoded_data = RleDecodeGlyphData((GX_COMPRESSED_GLYPH*)glyph, GetFontBits(font_format));
        input_data = decoded_data;
    }
    else
    {
        input_data = glyph->gx_glyph_map;
    }

    if (input_data)
    {
        switch (font_format & GX_FONT_FORMAT_BPP_MASK)
        {
        case GX_FONT_FORMAT_8BPP:
            rotated_data = Rotate8bitGlyphData(input_data, glyph->gx_glyph_width, glyph->gx_glyph_height);
            break;

        case GX_FONT_FORMAT_4BPP:
            rotated_data = Rotate4bitGlyphData(input_data, glyph->gx_glyph_width, glyph->gx_glyph_height);
            break;

        case GX_FONT_FORMAT_1BPP:
            rotated_data = Rotate1bitGlyphData(input_data, glyph->gx_glyph_width, glyph->gx_glyph_height);
            break;
        }
    }

    if ((font_format & GX_FONT_FORMAT_COMPRESSED) && rotated_data)
    {
        if (decoded_data)
        {
            delete decoded_data;
        }

        GX_COMPRESSED_GLYPH cglyph;

        cglyph.gx_glyph_map = rotated_data;
        cglyph.gx_glyph_width = glyph->gx_glyph_height;
        cglyph.gx_glyph_height = glyph->gx_glyph_width;

        RleEncodeGlyphData(&cglyph, GetFontBits(font_format));
        *rotated_map = (GX_UBYTE*)cglyph.gx_glyph_map;
        *rotated_map_size = cglyph.gx_glyph_map_size;
    }
    else
    {
        *rotated_map = rotated_data;
        *rotated_map_size = 0;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteFontPage(const GX_FONT *font, CString &name, int page, BOOL lastpage, BOOL custom_file_enabled)
{
    GX_CHAR_CODE charval;
    GX_CHAR_CODE index;

    const GX_GLYPH *glyph;
 
    const UCHAR *data;
    UCHAR* rotated_data = NULL;
    CString out;
    CString val;
    CString link;
    int datasize;
    int bytes_written = 0;
    int max_ascent = 0;
    int max_descent = 0;
    int max_height = 0;
    int guix_version = m_project->mHeader.guix_version;
    int* mapsize_list = GX_NULL;
    int  mapsize;

    if (!font)
    {
        return;
    }

    if (IsRotatedResourceSupported(m_project, m_display))
    {
        mapsize_list = new int[font->gx_font_last_glyph - font->gx_font_first_glyph + 1];
    }

    for (charval = font->gx_font_first_glyph; charval <= font->gx_font_last_glyph; charval++ )
    {
        index = charval - font->gx_font_first_glyph;

        if (font->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
        {
            glyph = (GX_GLYPH *)&font->gx_font_glyphs.gx_font_compressed_glyphs[index];
        }
        else if (font->gx_font_format & GX_FONT_FORMAT_KERNING)
        {
            glyph = (GX_GLYPH *)&font->gx_font_glyphs.gx_font_kerning_glyphs[index];
        }
        else
        {
            glyph = &font->gx_font_glyphs.gx_font_normal_glyphs[index];
        }

        if (IsRotatedResourceSupported(m_project, m_display))
        {
            RotateGlyphData(glyph, font->gx_font_format, &rotated_data, &mapsize);

            if (font->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
            {
                datasize = mapsize & 0x7fff;
            }
            else
            {
                datasize = GetRowPitch(glyph->gx_glyph_height, GetFontBits(font->gx_font_format));
                datasize *= glyph->gx_glyph_width;
                mapsize = datasize;
            }

            mapsize_list[index] = mapsize;
        }
        else
        {
            if (font->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
            {
                datasize = ((GX_COMPRESSED_GLYPH*)glyph)->gx_glyph_map_size & 0x7fff;
            }
            else
            {
                datasize = GetRowPitch(glyph->gx_glyph_width, GetFontBits(font->gx_font_format));
                datasize *= glyph->gx_glyph_height;
            }
        }


        if (!datasize)
        {
            continue;
        }

        out.Format(_T("static GX_CONST GX_UBYTE FONT_%s_char_%2x[%u] =\n{\n"), name, charval, datasize);
        FileWrite(out);

        bytes_written = 0;
        data = glyph->gx_glyph_map;

        out = CString("    ");

        BOOL written = TRUE;

        if (rotated_data)
        {
            data = rotated_data;
        }
        else
        {
            data = glyph->gx_glyph_map;
        }

        for (int i = 0; i < datasize; i++)
        {
            val.Format(_T("0x%02x"), *data);
            out += val;
            if (i != (datasize - 1))
            {
                out += ", ";
            }
            written = CheckLineFeed(out);
            data++;
        }

        if (rotated_data)
        {
            delete rotated_data;
        }

        if (!written)
        {
            FileWrite(out);
        }
        out = CString("\n};\n");
        FileWrite(out);

        /* Write glyph kerning table after it's map data. */
        if (font->gx_font_format & GX_FONT_FORMAT_KERNING)
        {
            GX_CONST GX_KERNING_GLYPH *kerning_glyph = &font->gx_font_glyphs.gx_font_kerning_glyphs[index];
            if (kerning_glyph -> gx_kerning_table)
            {
                WriteKerningTable(const_cast<GX_UBYTE *>(kerning_glyph->gx_kerning_table), name, charval);
            }
        }
    }
   
    /* Print out the font table */
    CString struct_name;
    CString glyph_cast_type = _T("");
    if (font->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
    {
        struct_name = _T("GX_COMPRESSED_GLYPH");
        glyph_cast_type = _T("(GX_CONST GX_GLYPH *)");
    }
    else if (font->gx_font_format & GX_FONT_FORMAT_KERNING)
    {
        struct_name = _T("GX_KERNING_GLYPH");
        glyph_cast_type = _T("(GX_CONST GX_GLYPH *)");
    }
    else
    {
        struct_name = _T("GX_GLYPH");
    }

    /* Write warning text on purpose. */
    if (font->gx_font_format & GX_FONT_FORMAT_KERNING)
    {
        out.Format(_T("#ifndef GX_FONT_KERNING_SUPPORT\n#error GX_FONT_KERNING_SUPPORT should be defined if \'Generate Kerning Info\' is selected in font edit dialog.\n#endif\n"));
        FileWrite(out);
    }

    out.Format(_T("static GX_CONST %s %s_FONT_PAGE_%d_GLYPHS[%u] =\n{\n"),
         struct_name, name, page, (font->gx_font_last_glyph - font->gx_font_first_glyph + 1));
    FileWrite(out);

    for (charval = font->gx_font_first_glyph; charval <= font->gx_font_last_glyph; charval++ )
    {
        index = charval - font->gx_font_first_glyph;
        CString kerning_table_name(_T("0"));
        
        if (font->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
        {
            glyph = (GX_GLYPH *)&font->gx_font_glyphs.gx_font_compressed_glyphs[index];
        }
        else if (font->gx_font_format & GX_FONT_FORMAT_KERNING)
        {
            glyph = (GX_GLYPH *)&font->gx_font_glyphs.gx_font_kerning_glyphs[index];
            if (((GX_KERNING_GLYPH *)glyph)->gx_kerning_table)
            {
                kerning_table_name.Format(_T("FONT_%s_char_%2x_kerning_table"), name, charval);
            }
        }
        else
        {
            glyph = &font->gx_font_glyphs.gx_font_normal_glyphs[index];
        }

        if (mapsize_list)
        {
            mapsize = mapsize_list[index];
            datasize = mapsize & 0x7fff;
        }
        else
        {
            if (font->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
            {
                mapsize = ((GX_COMPRESSED_GLYPH*)glyph)->gx_glyph_map_size;
                datasize = mapsize & 0x7fff;
            }
            else
            {
                datasize = GetRowPitch(glyph->gx_glyph_width, GetFontBits(font->gx_font_format));
                datasize *= glyph->gx_glyph_height;
            }
        }

        if (!datasize)
        {
            out.Format(_T("    {GX_NULL, "));
        }
        else
        {
            out.Format(_T("    {FONT_%s_char_%2x, "), name, charval);
        }
        FileWrite(out);

        if (guix_version < 50207)
        {
            //Generate old format for older libraries
            out.Format(_T("%d, %d, %d, %d, %u, %u}"),
                glyph->gx_glyph_ascent,
                glyph->gx_glyph_descent,
                glyph->gx_glyph_advance,
                glyph->gx_glyph_leading,
                glyph->gx_glyph_width,
                glyph->gx_glyph_height);
        }
        else if (guix_version < 50303)
        {
            //Generate new format for library version 5.2.6 or greater
            if (font->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
            {
                datasize = mapsize;
            }

            out.Format(_T("%d, %d, %d, %d, %d, %u, %u}"),
                datasize,
                glyph->gx_glyph_ascent,
                glyph->gx_glyph_descent,
                glyph->gx_glyph_advance,
                glyph->gx_glyph_leading,
                glyph->gx_glyph_width,
                glyph->gx_glyph_height);
        }
        else
        {
            //Generate new format for library version 5.3.3 or greater
            if (font->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
            {
                out.Format(_T("%d, %d, %d, %d, %u, %u, %d}"),
                    glyph->gx_glyph_ascent,
                    glyph->gx_glyph_descent,
                    glyph->gx_glyph_advance,
                    glyph->gx_glyph_leading,
                    glyph->gx_glyph_width,
                    glyph->gx_glyph_height,
                    mapsize);
            }
            else if (font->gx_font_format & GX_FONT_FORMAT_KERNING)
            {
                out.Format(_T("%d, %d, %d, %d, %u, %u, %s}"),
                    glyph->gx_glyph_ascent,
                    glyph->gx_glyph_descent,
                    glyph->gx_glyph_advance,
                    glyph->gx_glyph_leading,
                    glyph->gx_glyph_width,
                    glyph->gx_glyph_height,
                    kerning_table_name);
            }
            else 
            {
                out.Format(_T("%d, %d, %d, %d, %u, %u}"),
                    glyph->gx_glyph_ascent,
                    glyph->gx_glyph_descent,
                    glyph->gx_glyph_advance,
                    glyph->gx_glyph_leading,
                    glyph->gx_glyph_width,
                    glyph->gx_glyph_height);
            }
        }

        FileWrite(out);

        if(charval != font->gx_font_last_glyph)
        {
            FileWrite(CString(",\n"));
        }
        else
        {
            FileWrite(CString("\n};\n\n"));
        }
    }

    if (mapsize_list)
    {
        delete mapsize_list;
        mapsize_list = NULL;
    }

    /* Print the GX_FONT  */
    
    if (page > 1)
    {
        out.Format(_T("static GX_CONST GX_FONT %s_PAGE_%d =\n"), name, page);
    }
    else
    {
        if (custom_file_enabled)
        {
            out.Format(_T("GX_CONST GX_FONT %s = \n"), name);
        }
        else
        {
            out.Format(_T("static GX_CONST GX_FONT %s = \n"), name);
        }
    }

    CString font_format(_T(""));

    switch (font->gx_font_format & GX_FONT_FORMAT_BPP_MASK)
    {
    case GX_FONT_FORMAT_1BPP:
        font_format += "GX_FONT_FORMAT_1BPP";
        break;

    case GX_FONT_FORMAT_2BPP:
        font_format += "GX_FONT_FORMAT_2BPP";
        break;

    case GX_FONT_FORMAT_4BPP:
        font_format += "GX_FONT_FORMAT_4BPP";
        break;

    case GX_FONT_FORMAT_8BPP:
        font_format += "GX_FONT_FORMAT_8BPP";
        break;
    }

    if (font->gx_font_format & GX_FONT_FORMAT_COMPRESSED)
    {
        font_format += "|GX_FONT_FORMAT_COMPRESSED";
    }

    if (font->gx_font_format & GX_FONT_FORMAT_FREETYPE)
    {
        font_format += "|GX_FONT_FORMAT_FREETYPE";
    }

    if (guix_version >= 50402)
    {
        // font kerning suppot was not added until release 5.4.2
        if (font->gx_font_format & GX_FONT_FORMAT_KERNING)
        {
            font_format += "|GX_FONT_FORMAT_KERNING";
        }
    }

    if (guix_version >=  50500)
    {
        // support for this style flag was not added until release 5.5.0
        if (font->gx_font_format & GX_FONT_FORMAT_REVERSED_ORDER)
        {
            font_format += "|GX_FONT_FORMAT_REVERSED_ORDER";
        }
    }

    if (IsRotatedResourceSupported(m_project, m_display))
    {
        switch (m_project->mDisplays[m_display].rotation_angle)
        {
        case GX_SCREEN_ROTATION_CW:
            font_format += "|GX_FONT_FORMAT_ROTATED_90";
            break;

        case GX_SCREEN_ROTATION_CCW:
            font_format += "|GX_FONT_FORMAT_ROTATED_270";
            break;
        }
    }

    if (guix_version <= 50402)
    {
        link.Format(_T("{\n")
            _T("    %s,        /* format */\n")
            _T("    0,         /* line pre-space */\n")
            _T("    0,         /* line post-space */ \n")
            _T("    %u,        /* font data height */\n")
            _T("    %u,        /* font baseline offset */\n")
            _T("    0x%x,    /* first glyph within data page */\n")
            _T("    0x%x,    /* last glyph within data page */\n")
            _T("    %s%s_FONT_PAGE_%d_GLYPHS,    /* pointer to glyph data */\n"),
                font_format,
                font->gx_font_line_height,
                font->gx_font_baseline,
                font->gx_font_first_glyph,
                font->gx_font_last_glyph,
                glyph_cast_type, name, page);
    }
    else
    {
        link.Format(_T("{\n")
            _T("    %s,        /* format */\n")
            _T("    0,         /* line pre-space */\n")
            _T("    0,         /* line post-space */ \n")
            _T("    %u,        /* font data height */\n")
            _T("    %u,        /* font baseline offset */\n")
            _T("    0x%x,    /* first glyph within data page */\n")
            _T("    0x%x,    /* last glyph within data page */\n")
            _T("    {%s%s_FONT_PAGE_%d_GLYPHS},    /* pointer to glyph data */\n"),
                font_format,
                font->gx_font_line_height,
                font->gx_font_baseline,
                font->gx_font_first_glyph,
                font->gx_font_last_glyph,
                glyph_cast_type, name, page);
    }

    out += link;
    if (lastpage)
    {
        out += "    GX_NULL       /* next font page */\n";
    }
    else
    {
        link.Format(_T("    &%s_PAGE_%d  /* next font page */\n"), name, page + 1);
        out += link;
    }
    out += "};\n\n";
    FileWrite(out);
}


////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WritePixelmapStructure(res_info *pixinfo, int frame_id)
{
    CString out;

    /* Now write out the main structure. */

    CString name = MakePixelmapName(pixinfo, frame_id);

    out.Format(_T("GX_CONST GX_PIXELMAP %s_%s_%s_pixelmap =\n{\n"), UpperDisplayName(), m_ThemeName.MakeUpper(), name);

    FileWrite(out);

    out.Format(_T("    0x%08x,         /* major version */\n"), GX_CONVERT_VER);
    FileWrite(out);

    out.Format(_T("    0x%08x,         /* minor version */\n"), GX_CONVERT_SUBVER);
    FileWrite(out);

    BOOL orFlag = FALSE;
    out = CString("    ");

    if(m_map->gx_pixelmap_flags & GX_PIXELMAP_COMPRESSED)
    {
        out += "GX_PIXELMAP_COMPRESSED";
        orFlag = TRUE;
    }

    if(m_map->gx_pixelmap_flags & GX_PIXELMAP_ALPHA)
    {
        if (orFlag)
        {
            out += '|';
        }
        out += "GX_PIXELMAP_ALPHA";
        orFlag = TRUE;
    }

    if(m_map->gx_pixelmap_flags & GX_PIXELMAP_TRANSPARENT)
    {
        if (orFlag)
        {
            out += '|';
        }
        out += "GX_PIXELMAP_TRANSPARENT";
        orFlag = TRUE;
    }

    if(m_map -> gx_pixelmap_flags & GX_PIXELMAP_RAW_FORMAT)
    {
        if (orFlag)
        {
            out += '|';
        }
        out += "GX_PIXELMAP_RAW_FORMAT";
        orFlag = TRUE;
    }

    if (IsRotatedResourceSupported(m_project, m_display))
    {
        switch (m_project->mDisplays[m_display].rotation_angle)
        {
        case GX_SCREEN_ROTATION_CW:
            if (orFlag)
            {
                out += '|';
            }
            if (m_project->mHeader.guix_version >= GX_VERSION_PIXELMAP_ROTATION_FLAGS_FIX)
            {
                out += "GX_PIXELMAP_ROTATED_CW";
            }
            else
            {
                out += "GX_PIXELMAP_ROTATED_90";
            }
            orFlag = TRUE;
            break;

        case GX_SCREEN_ROTATION_CCW:
            if (orFlag)
            {
                out += '|';
            }
            if (m_project->mHeader.guix_version >= GX_VERSION_PIXELMAP_ROTATION_FLAGS_FIX)
            {
                out += "GX_PIXELMAP_ROTATED_CCW";
            }
            else
            {
                out += "GX_PIXELMAP_ROTATED_270";
            }
            orFlag = TRUE;
            break;
        }
    }

    if(!orFlag)
    {
        out += "0,         /* flags*/\n";
    }
    else
    {
        out += ",         /* flags*/\n";
    }
    FileWrite(out);

    out.Format(_T("    %s,         /* Format */\n"), GetColorFormatName(m_map->gx_pixelmap_format));
    FileWrite(out);
    out.Format(_T("    (GX_UBYTE *) %s_%s_%s_pixelmap_data,\n"), UpperDisplayName(), m_ThemeName.MakeUpper(), name);
    FileWrite(out);

    out.Format(_T("    sizeof(%s_%s_%s_pixelmap_data),    /* the size of pixelmap_data*/\n"), UpperDisplayName(), m_ThemeName.MakeUpper(), name);
    FileWrite(out);

    if(m_map -> gx_pixelmap_aux_data_size)
    {
        if (m_map->gx_pixelmap_format == GX_COLOR_FORMAT_8BIT_PALETTE)
        {
            if (pixinfo->palette_type == PALETTE_TYPE_PRIVATE)
            {
                out.Format(_T("    (GX_UBYTE *) %s_%s_palette,\n"),
                    m_project->mDisplays[m_display].name, pixinfo->name);          
                FileWrite(out);
                out.Format(_T("    sizeof(%s_%s_palette),    /* the size of pixelmap_data*/\n"),
                    m_project->mDisplays[m_display].name, pixinfo->name);
            }
            else
            {
                out.Format(_T("    (GX_UBYTE *) %s_shared_palette,\n"),
                    m_project->mDisplays[m_display].name);
                FileWrite(out);
                out.Format(_T("    sizeof(%s_shared_palette),    /* the size of pixelmap_data*/\n"),
                    m_project->mDisplays[m_display].name);

            }
        }
        else
        {
            out.Format(_T("    (GX_UBYTE *) %s_%s_%s_pixelmap_aux_data,\n"),
                UpperDisplayName(), m_ThemeName.MakeUpper(), name);
            FileWrite(out);

            out.Format(_T("    sizeof(%s_%s_%s_pixelmap_aux_data),    /* the size of pixelmap_data*/\n"),
                UpperDisplayName(), m_ThemeName.MakeUpper(), name);

        }

    }
    else
    {
        out.Format(_T("    NULL,\n"));
        FileWrite(out);
        out.Format(_T("    0,     /* auxiliary data size*/\n"));
    }
    FileWrite(out);

    out.Format(_T("    0x%02x,    /* used for transparent iamges*/\n"), m_map->gx_pixelmap_transparent_color);
    FileWrite(out);

    out.Format(_T("    %u,        /* width in pixel*/\n"), m_map->gx_pixelmap_width);	// height
    FileWrite(out);

    out.Format(_T("    %u        /* height in pixel*/\n"), m_map->gx_pixelmap_height);
    FileWrite(out);

    out.Format(_T("};\n"));
    FileWrite(out);
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteRawPixelmap(res_info *pixinfo, int frame_id)
{
    CString path;
    CString out;
    CString val;
    unsigned char *data_p;
    UCHAR buffer[32];
    long file_size;
    long total_data_size;
    long total_bytes_written;
    int chunk_size;

    path = MakeAbsolutePathname(pixinfo->pathinfo);
    FILE *file = _tfopen(path.GetBuffer(), _T("rb"));

    if (!file)
    {
        return;
    }

    fseek(file, 0, SEEK_END);
    file_size = ftell(file);
    
    // calculate padded size
    if (IsRenesasDave2D(m_project) || IS_RZ_TARGET)
    {
        total_data_size = (file_size | 0x07) + 1; 
    }
    else
    {
        total_data_size = file_size;
    }

    fseek(file, 0, SEEK_SET);

    out.Format(_T("\n/* %s_%s pixelmap data */\n\n"), m_ThemeName.MakeUpper(), pixinfo->name);
    FileWrite(out);

    // force 8 byte alignment for Dave2D target 
    if (IsRenesasDave2D(m_project) || IS_RZ_TARGET)
    {
        out.Format(_T("#ifdef WIN32\nstatic GX_CONST GX_UBYTE %s_%s_%s_pixelmap_data[%d] =\n#else\n"),
            UpperDisplayName(), m_ThemeName.MakeUpper(), pixinfo->name, total_data_size);

        switch(m_project->mHeader.target_tools)
        {
        case TOOLS_GNU:
            FileWrite(out);
            out.Format(_T("static GX_CONST GX_UBYTE %s_%s_%s_pixelmap_data[%d] __attribute__((aligned(8))) ="),
                UpperDisplayName(), m_ThemeName.MakeUpper(), pixinfo->name, total_data_size);
            out += "\n#endif\n{\n";
            break;

        case TOOLS_IAR:
            FileWrite(out);
            out.Format(_T("#pragma data_alignment=8\nstatic GX_CONST GX_UBYTE %s_%s_%s_pixelmap_data[%d] ="),
                UpperDisplayName(), m_ThemeName.MakeUpper(), pixinfo->name, total_data_size);
            out += "\n#endif\n{\n";
            break;

        default:
            out.Format(_T("static GX_CONST GX_UBYTE %s_%s_%s_pixelmap_data[%d] =\n{\n"),
                UpperDisplayName(), m_ThemeName.MakeUpper(), pixinfo->name, total_data_size);
            break;
        }

        FileWrite(out);
    }
    else
    {
        out.Format(_T("static GX_CONST GX_UBYTE %s_%s_%s_pixelmap_data[%d] =\n{\n"),
            UpperDisplayName(), m_ThemeName.MakeUpper(), pixinfo->name, total_data_size);
        FileWrite(out);
    }

    total_bytes_written = 0;

    while(total_bytes_written < file_size)
    {
        chunk_size = fread(buffer, 1, 32, file);
        data_p = (unsigned char*) buffer;
        out = CString("    ");

        for(int i = 0; i < chunk_size; i++)
        {
            val.Format(_T("0x%02x"), *data_p);
            out += val;
            if (total_bytes_written != (total_data_size - 1))
            {
                out += ", ";
            }
            data_p++;
            total_bytes_written++;
        }
        out += CString("\n");
		FileWrite(out);
    }

    // add the padding
    if (total_bytes_written < total_data_size)
    {
        out = CString("    ");
        for(int i = total_bytes_written; i < total_data_size; i++)
        {
            val.Format(_T("0x%02x"), 0);
            out += val;
            if (i != (total_data_size - 1))
            {
                out += ", ";
            }
        }
        out += CString("\n");
		FileWrite(out);
    }
    out = CString("\n};\n");
    FileWrite(out);        
    fclose(file);

    // create a temp GX_PIXELMAP structure with updated fields, write the structure,
    // then restore the orginal pixelmap structure pointer.

    GX_PIXELMAP temp_map;
    GX_PIXELMAP *old_map = m_map;

    temp_map = (*old_map);
    temp_map.gx_pixelmap_aux_data = GX_NULL;
    temp_map.gx_pixelmap_aux_data_size = 0;
    temp_map.gx_pixelmap_data_size = total_data_size;
    temp_map.gx_pixelmap_flags |= GX_PIXELMAP_RAW_FORMAT;
    m_map = &temp_map;

    WritePixelmapStructure(pixinfo, frame_id);
}

GX_UBYTE* resource_gen::RotateUIntData(GX_CONST GX_UBYTE* data, INT width, INT height)
{
    int data_size = width * height;
    UINT* out_data = new UINT[data_size];
    UINT* put_row = out_data;
    UINT* put;
    int   putsign;

    GX_CONST UINT* get_row = (GX_CONST UINT*)data;
    GX_CONST UINT* get;

    if (m_project->mDisplays[m_display].rotation_angle == GX_SCREEN_ROTATION_CW)
    {
        put_row += (width - 1) * height;
        putsign = 1;
    }
    else
    {
        put_row += (height - 1);
        putsign = -1;
    }

    for (int row = 0; row < height; row++)
    {
        get = get_row;
        put = put_row;

        for (int col = 0; col < width; col++)
        {
            *put = *get;

            get++;
            put -= height * putsign;
        }

        get_row += width;
        put_row += putsign;
    }

    return (GX_UBYTE*)out_data;
}

GX_UBYTE* resource_gen::RotateUShortData(GX_CONST GX_UBYTE* data, INT width, INT height)
{
    int data_size = width * height;
    USHORT* out_data = new USHORT[data_size];
    USHORT* put_row = out_data;
    USHORT* put;
    int     putsign;

    GX_CONST USHORT* get_row = (GX_CONST USHORT*)data;
    GX_CONST USHORT* get;

    if (m_project->mDisplays[m_display].rotation_angle == GX_SCREEN_ROTATION_CW)
    {
        put_row += (width - 1) * height;
        putsign = 1;
    }
    else
    {
        put_row += (height - 1);
        putsign = -1;
    }

    for (int row = 0; row < height; row++)
    {
        get = get_row;
        put = put_row;

        for (int col = 0; col < width; col++)
        {
            *put = *get;

            get++;
            put -= height * putsign;
        }

        get_row += width;
        put_row += putsign;
    }

    return (GX_UBYTE*)out_data;
}

GX_UBYTE* resource_gen::RotateUCharData(GX_CONST GX_UBYTE* data, INT width, INT height)
{
    int data_size = width * height;
    GX_UBYTE* out_data = new GX_UBYTE[data_size];
    GX_UBYTE* put_row = out_data;
    GX_UBYTE* put;
    int       putsign;

    GX_CONST GX_UBYTE* get_row = data;
    GX_CONST GX_UBYTE* get;

    if (m_project->mDisplays[m_display].rotation_angle == GX_SCREEN_ROTATION_CW)
    {
        put_row += (width - 1) * height;
        putsign = 1;
    }
    else
    {
        put_row += (height - 1);
        putsign = -1;
    }

    for (int row = 0; row < height; row++)
    {
        get = get_row;
        put = put_row;

        for (int col = 0; col < width; col++)
        {
            *put = *get;

            get++;
            put -= height * putsign;
        }

        get_row += width;
        put_row += putsign;
    }

    return out_data;
}

VOID resource_gen::RotatePixelmap(GX_PIXELMAP* map)
{
    GX_UBYTE* data;
    GX_UBYTE* auxdata;

    if (!map->gx_pixelmap_data)
    {
        return;
    }

    switch (map->gx_pixelmap_format)
    {
    case GX_COLOR_FORMAT_24XRGB:
    case GX_COLOR_FORMAT_24BGRX:
    case GX_COLOR_FORMAT_32ARGB:
    case GX_COLOR_FORMAT_32RGBA:
    case GX_COLOR_FORMAT_32ABGR:
    case GX_COLOR_FORMAT_32BGRA:
        data = RotateUIntData(map->gx_pixelmap_data, map->gx_pixelmap_width, map->gx_pixelmap_height);
        break;

    case GX_COLOR_FORMAT_565RGB:
    case GX_COLOR_FORMAT_565BGR:
    case GX_COLOR_FORMAT_4444ARGB:
    case GX_COLOR_FORMAT_4444BGRA:
    case GX_COLOR_FORMAT_5551BGRX:
    case GX_COLOR_FORMAT_1555XRGB:
        data = RotateUShortData(map->gx_pixelmap_data, map->gx_pixelmap_width, map->gx_pixelmap_height);

        if (map->gx_pixelmap_aux_data)
        {
            auxdata = RotateUCharData(map->gx_pixelmap_aux_data, map->gx_pixelmap_width, map->gx_pixelmap_height);
            delete map->gx_pixelmap_aux_data;
            map->gx_pixelmap_aux_data = auxdata;
        }
        break;

    default:
        data = RotateUCharData(map->gx_pixelmap_data, map->gx_pixelmap_width, map->gx_pixelmap_height);
        break;
    }

    delete map->gx_pixelmap_data;
    map->gx_pixelmap_data = data;

    GX_SWAP_VALS(map->gx_pixelmap_width, map->gx_pixelmap_height);
}

GX_PIXELMAP* resource_gen::RotatePixelmap(res_info* info, int theme_id, GX_PIXELMAP *map, int frame_id)
{
    GX_PIXELMAP* rotated_map = NULL;

    image_reader *pReader = NULL;
    CString abspath;
    IMAGE_INFO* default_image_info = NULL;
    int frame_count = 1;

    if (info->is_default && info->pathinfo.pathname.IsEmpty())
    {
        // Read image from internally linked system png data.
        PIXELMAP_RECORD* record = studiox_project::GetDefaultPixelmapRecord(info->name);
        if (record)
        {
            default_image_info = record->image_info;
            pReader = image_reader::CreateProperReader(default_image_info->data, default_image_info->data_len);
        }
    }
    else
    {
        abspath = MakeAbsolutePathname(info->pathinfo);
        pReader = image_reader::CreateProperReader(abspath);
        frame_count = image_reader::GetFrameCount(abspath);
    }

    if (pReader)
    {
        pReader->SetDither(info->dither);

        if (info->keep_alpha)
        {
            pReader->SetSaveAlphaVal(TRUE);
        }
        else
        {
            pReader->SetSaveAlphaVal(FALSE);
        }

        pReader->SetOutputColorFormat(map->gx_pixelmap_format, m_project->GetDisplayColorFormat(info));

        if (map->gx_pixelmap_format == GX_COLOR_FORMAT_8BIT_PALETTE)
        {
            switch (info->palette_type)
            {
            case PALETTE_TYPE_SHARED:
            case PALETTE_TYPE_PRIVATE:
                if (m_project->mDisplays[m_display].colorformat == GX_COLOR_FORMAT_8BIT_PALETTE)
                {
                    theme_info *info = &m_project->mDisplays[m_display].themes[theme_id];
                    if (info->palette)
                    {
                        pReader->SetPalette(info->palette, info->palette_total_size, info->palette_total_size);
                    }
                }
                else
                {
                    palette_info private_palette;

                    private_palette.total_size = map->gx_pixelmap_aux_data_size / sizeof(GX_COLOR);
                    private_palette.palette = new GX_COLOR[private_palette.total_size];
                    memcpy(private_palette.palette, (GX_COLOR*)map->gx_pixelmap_aux_data, map->gx_pixelmap_aux_data_size); /* Use case of memcpy is verified. */
                    pReader->SetPalette(private_palette.palette, private_palette.total_size, private_palette.total_size);
                }
                break;

            default:
                ErrorMsg("Internal Error: Invalid image palette type");
                delete pReader;
                return FALSE;
            }
        }

        BOOL result;

        if (default_image_info)
        {
            result = pReader->ReadImage(default_image_info->data, default_image_info->data_len);
        }
        else
        {
            result = pReader->ReadImage(abspath, frame_id);
        }

        if (result)
        {
            rotated_map = pReader->GetPixelmap();
            RotatePixelmap(rotated_map);
        }

        if (rotated_map)
        {
            // now compress the image
            if (info->compress)
            {
                int result;
                pReader->DoCompress(TRUE);
                if (IsRenesasDave2D(m_project))
                {
                    result = pReader->RleEncode(rotated_map, TRUE);
                }
                else
                {
                    result = pReader->RleEncode(rotated_map);
                }

                if (result == FALSE)
                {
                    info->compress = FALSE;
                }
            }

            if (m_project->mDisplays[m_display].rotation_angle == GX_SCREEN_ROTATION_CW)
            {
                rotated_map->gx_pixelmap_flags |= GX_PIXELMAP_ROTATED_CW;
            }
            else
            {
                rotated_map->gx_pixelmap_flags |= GX_PIXELMAP_ROTATED_CCW;
            }

            GX_SWAP_VALS(rotated_map->gx_pixelmap_width, rotated_map->gx_pixelmap_height);

            delete pReader;
        }
    }

    return rotated_map;
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WritePixelmapData(res_info *pixinfo, int theme_id, int frame_id)
{
//    CString out;

    // m_map should be intialized by caller, and might not be same image pointed to by
    // info if output format does not match display format.

    if (!m_map)
    {
        return;
    }

    GX_PIXELMAP* rotated_map = GX_NULL;

    if (IsRotatedResourceSupported(m_project, m_display))
    {
        rotated_map = RotatePixelmap(pixinfo, theme_id, m_map, frame_id);
        m_map = rotated_map;
    }

    if (m_map->gx_pixelmap_flags & GX_PIXELMAP_COMPRESSED &&
        m_map->gx_pixelmap_flags & GX_PIXELMAP_TARGA)
    {
        if (IsRenesasDave2D(m_project) &&
            (m_project->mHeader.target_tools == TOOLS_CCRX))
        {
                WriteCCRXCompatibleTargaStream(pixinfo, frame_id);
        }
        else
        {
            // All targa formats are just byte streams, use UCHAR
            WriteUcharData(pixinfo, frame_id);
        }
    }
    else
    {    
        switch(m_map->gx_pixelmap_format)
        {
        case GX_COLOR_FORMAT_24XRGB:
        case GX_COLOR_FORMAT_24BGRX:
        case GX_COLOR_FORMAT_32ARGB: 
        case GX_COLOR_FORMAT_32RGBA:
        case GX_COLOR_FORMAT_32ABGR:
        case GX_COLOR_FORMAT_32BGRA:
            WriteUintData(pixinfo, frame_id);
            break;

        case GX_COLOR_FORMAT_565RGB:
        case GX_COLOR_FORMAT_565BGR:
        case GX_COLOR_FORMAT_4444ARGB:
        case GX_COLOR_FORMAT_4444BGRA:
        case GX_COLOR_FORMAT_5551BGRX: 
        case GX_COLOR_FORMAT_1555XRGB:
            if (m_big_endian &&
                (m_map->gx_pixelmap_flags & GX_PIXELMAP_COMPRESSED) &&
                (m_map->gx_pixelmap_flags & GX_PIXELMAP_ALPHA))
            {
                WriteBigEndianCompressedUshortData(pixinfo, frame_id);
            }
            else
            {
                WriteUshortData(pixinfo, frame_id);
            }
            break;

        case GX_COLOR_FORMAT_8BIT_PACKED_PIXEL:
            if ((m_map->gx_pixelmap_flags & GX_PIXELMAP_COMPRESSED) &&
                (m_map->gx_pixelmap_flags & GX_PIXELMAP_ALPHA))
            {
                WriteUshortData(pixinfo, frame_id);
            }
            else
            {
                WriteUcharData(pixinfo, frame_id);
            }
            break;

        default:
            WriteUcharData(pixinfo, frame_id);
            break;
        }
    }

    if(m_map->gx_pixelmap_aux_data)
    {
        if (pixinfo->output_color_format == GX_COLOR_FORMAT_8BIT_PALETTE)
        {
            if (pixinfo->palette_type == PALETTE_TYPE_PRIVATE)
            {
                if (!mPrivatePaletteWritten)
                {
                    WritePalette(m_map->gx_pixelmap_aux_data_size / 4,
                        (GX_COLOR*)m_map->gx_pixelmap_aux_data, pixinfo->name);

                    mPrivatePaletteWritten = TRUE;
                }
            }
            else
            {
                if (!mDefaultPaletteWritten)
                {
                    WritePalette(m_map->gx_pixelmap_aux_data_size / 4,
                        (GX_COLOR*)m_map->gx_pixelmap_aux_data, CString("shared"));

                    mDefaultPaletteWritten = TRUE;
                }
            }
        }
        else
        {
            WriteUcharAuxData(pixinfo, frame_id);
        }
    }

    WritePixelmapStructure(pixinfo, frame_id);

    if (rotated_map)
    {
        pixelmap_destroy(rotated_map);
    }
}



#ifndef COLWIDTH
#define COLWIDTH 80
#endif

////////////////////////////////////////////////////////////////////////////////////////////////
BOOL resource_gen::CheckLineFeed(CString &out)
{
	if(out.GetLength() >= COLWIDTH)
	{
        out += CString("\n");
		FileWrite(out);

        out = CString("    ");
        return TRUE;
	}
    return FALSE;
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteUintData(res_info *info, int res_index)
{
    CString out;
    CString val;
    unsigned int *data_p;

    CString name = MakePixelmapName(info, res_index);

    out.Format(_T("\n/* %s_%s pixelmap data */\n\n"), m_ThemeName.MakeUpper(), name);
    FileWrite(out);

    //if (!info->qualifier.IsEmpty())
    //{
    //    out.Format("%s\n", info->qualifier);
    //    FileWrite(out);
    //}

    out.Format(_T("static GX_CONST UINT %s_%s_%s_pixelmap_data[%d] =\n{\n"),
        UpperDisplayName(), m_ThemeName.MakeUpper(), name, m_map->gx_pixelmap_data_size / 4);


    FileWrite(out);

    out = CString("    ");

    data_p = (unsigned int*) m_map->gx_pixelmap_data;

    BOOL written = TRUE;
    for(unsigned int i = 0; i < m_map->gx_pixelmap_data_size / 4; i++)
    {
        val.Format(_T("0x%08x"), *data_p);
        out += val;
        if (i != ((m_map->gx_pixelmap_data_size / 4) - 1))
        {
            out += ", ";
        }
        written = CheckLineFeed(out);
        data_p++;
    }
    if (!written)
    {
        FileWrite(out);
    }
    out = CString("\n};\n");
    FileWrite(out);
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteCCRXCompatibleTargaStream(res_info* info, int res_index)
{
    /* Targa stream is bytes, but Dave2D requires 4 byte data alignment. CCRX doesn't
        support any type of alignment pragma, so we write the byte data out as Ulongs.
    */
     
    CString out;
    CString val;
    UCHAR *pData;
    ULONG dataval;
    unsigned int loop;
    unsigned int bytes_left;
    unsigned int bytes_written;

    CString name = MakePixelmapName(info, res_index);

    out.Format(_T("\n/* %s_%s pixelmap data */\n\n"), m_ThemeName.MakeUpper(), name);
    FileWrite(out);

    out.Format(_T("static GX_CONST UINT %s_%s_%s_pixelmap_data[%d] =\n{\n"),
        UpperDisplayName(), m_ThemeName.MakeUpper(), name, (m_map->gx_pixelmap_data_size + 3) / 4);

    FileWrite(out);

    out = CString("    ");

    pData = (UCHAR *) m_map->gx_pixelmap_data;

    BOOL written = TRUE;
    bytes_written = 0;

    for (loop = 0; loop < m_map->gx_pixelmap_data_size / 4; loop++)
    {
        dataval = *pData++;
        dataval |= (*pData++) << 8;
        dataval |= (*pData++) << 16;
        dataval |= (*pData++) << 24;

        bytes_written += 4;

        val.Format(_T("0x%08x"), dataval);
        out += val;
        if (bytes_written != (m_map->gx_pixelmap_data_size))
        {
            out += ", ";
        }
        written = CheckLineFeed(out);
    }
 
    bytes_left = m_map->gx_pixelmap_data_size - bytes_written;

    if (bytes_left)
    {
        written = FALSE;
        dataval = 0;

        switch (bytes_left)
        {
        case 1:
            dataval = *pData++;
            break;

        case 2:
            dataval = *pData++;
            dataval |= (*pData++) << 8;
            break;

        case 3:
            dataval = *pData++;
            dataval |= (*pData++) << 8;
            dataval |= (*pData++) << 16;
            break;
        }
        val.Format(_T("0x%08x"), dataval);
        out += val;
    }

    if (!written)
    {
        FileWrite(out);
    }

    out = CString("\n};\n");
    FileWrite(out);
}


////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteUshortData(res_info *info, int frame_id)
{
    CString out;
    CString val;
    unsigned short *data_p;
    unsigned short data;

    CString name = MakePixelmapName(info, frame_id);

    out.Format(_T("\n/* %s_%s pixelmap data */\n\n"), m_ThemeName.MakeUpper(), name);
    FileWrite(out);

    out.Format(_T("static GX_CONST USHORT %s_%s_%s_pixelmap_data[%d] =\n{\n"),
        UpperDisplayName(), m_ThemeName.MakeUpper(), name, m_map->gx_pixelmap_data_size / 2);
    FileWrite(out);

    out = CString("    ");

    data_p = (unsigned short*) m_map -> gx_pixelmap_data;
    GX_UBYTE format = m_map ->gx_pixelmap_format;

    BOOL written = TRUE;

    for(unsigned int i = 0; i < m_map->gx_pixelmap_data_size / 2; i++)
    {
        data = *data_p;
        val.Format(_T("0x%04x"), data);
        out += val;
        if (i != ((m_map->gx_pixelmap_data_size / 2) - 1))
        {
            out += ", ";
        }        
        written = CheckLineFeed(out);
        data_p++;
    }
    if (!written)
    {
        FileWrite(out);
    }

    out = CString("\n};\n");
    FileWrite(out);        
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteBigEndianCompressedUshortData(res_info *info, int frame_id)
{

    CString out;
    CString val;
    unsigned short *pShort;
    unsigned char  *pByte;
    unsigned short  data;
    unsigned char   bcount;
    unsigned char   alpha;
    int pixels_to_write;
    ULONG bytes_written = 0;

    CString name = MakePixelmapName(info, frame_id);
    out.Format(_T("\n/* %s_%s pixelmap data */\n\n"), m_ThemeName.MakeUpper(), name);
    FileWrite(out);

    out.Format(_T("static GX_CONST USHORT %s_%s_%s_pixelmap_data[%d] =\n{\n"),
        UpperDisplayName(), m_ThemeName.MakeUpper(), name, m_map->gx_pixelmap_data_size / 2);
    FileWrite(out);

    out = CString("    ");

    pShort = (unsigned short*) m_map -> gx_pixelmap_data;
    GX_UBYTE format = m_map ->gx_pixelmap_format;

    BOOL written = TRUE;

    while(bytes_written < m_map->gx_pixelmap_data_size)
    {
        pByte = (unsigned char *) pShort;
        bcount = *pByte;
        
        if (bcount & 0x80)
        {
            pixels_to_write = 1;
        }
        else
        {
            pixels_to_write = bcount + 1;
        }

        for (int i = 0; i < pixels_to_write; i++)
        {
            pByte = (unsigned char *) pShort;
            
            bcount = *pByte++;
            alpha = *pByte++;
            pShort++;

            data = bcount;
            data <<= 8;
            data |= alpha;
            val.Format(_T("0x%04x"), data);
            out += val;
            out += ", ";
            data = *pShort++;
            val.Format(_T("0x%04x"), data);
            out += val;
            bytes_written += 4;

            if (bytes_written <= m_map->gx_pixelmap_data_size)
            {
                out += ", ";
            }        
            written = CheckLineFeed(out);
        }
    }
    if (!written)
    {
        FileWrite(out);
    }

    out = CString("\n};\n");
    FileWrite(out);        
}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteUcharData(res_info *info, int frame_id)
{
    CString out;
    CString val;
    unsigned char *data_p;

    CString name = MakePixelmapName(info, frame_id);
    out.Format(_T("\n/* %s_%s pixelmap data */\n\n"), m_ThemeName.MakeUpper(), name);
    FileWrite(out);

    if (IsRenesasDave2D(m_project))
    {
        out.Format(_T("#ifdef WIN32\nstatic GX_CONST GX_UBYTE %s_%s_%s_pixelmap_data[%d] =\n#else\n"),
            UpperDisplayName(), m_ThemeName.MakeUpper(), name, m_map->gx_pixelmap_data_size);

        switch (m_project->mHeader.target_tools)
        {
        case TOOLS_GNU:
            FileWrite(out);
            out.Format(_T("static GX_CONST GX_UBYTE %s_%s_%s_pixelmap_data[%d] __attribute__((aligned(4))) ="),
                UpperDisplayName(), m_ThemeName.MakeUpper(), name, m_map->gx_pixelmap_data_size);
            out += "\n#endif\n{\n";
            break;

        case TOOLS_IAR:
            FileWrite(out);
            out.Format(_T("#pragma data_alignment=4\nstatic GX_CONST GX_UBYTE %s_%s_%s_pixelmap_data[%d] ="),
                UpperDisplayName(), m_ThemeName.MakeUpper(), name, m_map->gx_pixelmap_data_size);
            out += "\n#endif\n{\n";
            break;

        default:
            out.Format(_T("static GX_CONST GX_UBYTE %s_%s_%s_pixelmap_data[%d] =\n{\n"),
                UpperDisplayName(), m_ThemeName.MakeUpper(), name, m_map->gx_pixelmap_data_size);
            break;
        }
    }
    else
    {
        out.Format(_T("static GX_CONST GX_UBYTE %s_%s_%s_pixelmap_data[%d] =\n{\n"),
            UpperDisplayName(), m_ThemeName.MakeUpper(), name, m_map->gx_pixelmap_data_size);
    }
    FileWrite(out);

    out = CString("    ");

    data_p = (unsigned char*) m_map->gx_pixelmap_data;
    BOOL written = TRUE;

    for(unsigned int i = 0; i < m_map->gx_pixelmap_data_size; i++)
    {
        val.Format(_T("0x%02x"), *data_p);
        out += val;
        if (i != (m_map->gx_pixelmap_data_size - 1))
        {
            out += ", ";
        }
        written = CheckLineFeed(out);
        data_p++;
    }
    if (!written)
    {
        FileWrite(out);
    }
    out = CString("\n};\n");
    FileWrite(out);        

}

////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteUcharAuxData(res_info *info, int frame_id)
{
    CString out;
    CString val;
    unsigned char *data_p;

    CString name = MakePixelmapName(info, frame_id);

    out.Format(_T("\n/* %s_%s auxiliary data */\n\n"), m_ThemeName.MakeUpper(), name);
    FileWrite(out);

    out.Format(_T("static GX_CONST GX_UBYTE %s_%s_%s_pixelmap_aux_data[%d] =\n{\n"),
        UpperDisplayName(), m_ThemeName.MakeUpper(), name, m_map->gx_pixelmap_aux_data_size);
    FileWrite(out);

    out = CString("    ");

    data_p = (unsigned char*) m_map->gx_pixelmap_aux_data;
    BOOL written = TRUE;

    for(unsigned int i = 0; i < m_map->gx_pixelmap_aux_data_size; i++)
    {
        val.Format(_T("0x%02x"), *data_p);
        out += val;
        if (i != (m_map->gx_pixelmap_aux_data_size - 1))
        {
            out += ", ";
        }
        written = CheckLineFeed(out);
        data_p++;
    }
    if (!written)
    {
        FileWrite(out);
    }
    out = CString("\n};\n");
    FileWrite(out);        
}

/////////////////////////////////////////////////////////////////////////////////////////////////
void resource_gen::WriteUintAuxData(res_info *info, int frame_id)
{
    CString out;
    CString val;
    unsigned int *data_p;

    CString name = MakePixelmapName(info, frame_id);

    out.Format(_T("\n/* %s_%s auxiliary data */\n\n"), m_ThemeName.MakeUpper(), name);
    FileWrite(out);

    out.Format(_T("static GX_CONST GX_COLOR %s_%s_%s_pixelmap_aux_data[%d] =\n{\n"),
        UpperDisplayName(), m_ThemeName.MakeUpper(), name, m_map->gx_pixelmap_aux_data_size / 4);
    FileWrite(out);

    out = CString("    ");

    data_p = (unsigned int*) m_map->gx_pixelmap_aux_data;
    BOOL written = TRUE;

    for(unsigned int i = 0; i < (m_map->gx_pixelmap_aux_data_size / 4); i++)
    {
        val.Format(_T("0x%08x"), *data_p);
        out += val;
        if (i != (m_map->gx_pixelmap_aux_data_size - 1))
        {
            out += ", ";
        }
        written = CheckLineFeed(out);
        data_p++;
    }
    if (!written)
    {
        FileWrite(out);
    }
    out = CString("\n};\n");
    FileWrite(out);  
}

////////////////////////////////////////////////////////////////////////////////////////////////
CString resource_gen::GetResourceFileName()
{
    CString name;

    CCommandInfo *pCmdInfo = GetCmdInfo();

    if (pCmdInfo->GetResourceFileName().IsEmpty())
    {
        if (m_project->mHeader.custom_resource_enabled && (!m_project->mHeader.custom_resource_file_name.IsEmpty()))
        {
            name = m_project->mHeader.custom_resource_file_name;

            if (m_project->CountEnabledDisplays() > 1)
            {
                name += "_";
                name += m_project->mDisplays[m_display].name;
            }
        }
        else
        {
            name = m_project->mHeader.project_name;

            if (m_num_displays > 1)
            {
                name += "_";
                name += m_project->mDisplays[m_display].name;
            }

            name += "_resources";
        }
    }
    else
    {
        name = pCmdInfo->GetResourceFileName();

        if (m_project->CountEnabledDisplays() > 1)
        {
            name += "_";
            name += m_project->mDisplays[m_display].name;
        }
    }

    return name;
}

////////////////////////////////////////////////////////////////////////////////////////////////
BOOL resource_gen::FontPageCompare(res_info *info_1, res_info *info_2)
{
    if (info_1->font_support_extended_unicode != info_2->font_support_extended_unicode)
    {
        //Font range is not equal
        return FALSE;
    }

    int page_count = NUM_FONT_CHAR_RANGES;
    if (info_1->font_support_extended_unicode)
    {
        page_count += NUM_FONT_EXTENDED_CHAR_RANGES;
    }

    for (int index = 0; index < page_count; index++)
    {
        if((info_1->font_pages[index].enabled != info_2->font_pages[index].enabled) ||
           (info_1->font_pages[index].first_char != info_2->font_pages[index].first_char) ||
           (info_1->font_pages[index].last_char != info_2->font_pages[index].last_char))
        {
            //Font range is not equal
            return FALSE;
        }
    }

    //Font range is equal
    return TRUE;
}

////////////////////////////////////////////////////////////////////////////////////////////////
int resource_gen::FindResourceReferenceTheme(res_info *info, int theme)
{
    // Check if the resource is equal to what in theme 0
    int refer_theme = -1;
    res_info *refer_info = NULL;
    CString abspath;
    CString refer_abspath;
    int index;
    int res_id;

    CCommandInfo *pCmdInfo = GetCmdInfo();
    GX_BOOL enabled;

    switch (info->type)
    {
    case RES_TYPE_FONT:
        for (index = 0; index < theme; index++)
        {
            if (pCmdInfo->IsNoGui())
            {
                enabled = pCmdInfo->IsThemeEnabled(m_project->mDisplays[m_display].themes[index].theme_name);
            }
            else
            {
                enabled = m_project->mDisplays[m_display].themes[index].gen_font_table;
            }

            if (enabled)
            {
                res_id = m_project->GetResourceId(m_display, info);
                refer_info = m_project->FindResource(m_display, index, info->type, res_id);

                if (refer_info)
                {
                    abspath = MakeAbsolutePathname(info->pathinfo);
                    refer_abspath = MakeAbsolutePathname(refer_info->pathinfo);

                    if ((abspath == refer_abspath) &&
                        (info->font_bits == refer_info->font_bits) &&
                        (info->font_height == refer_info->font_height) &&
                        FontPageCompare(info, refer_info))
                    {
                        refer_theme = index;
                    }
                }
                break;
            }
        }
        break;

    case RES_TYPE_PIXELMAP:
        for (index = 0; index < theme; index++)
        {
            if (pCmdInfo->IsNoGui())
            {
                enabled = pCmdInfo->IsThemeEnabled(m_project->mDisplays[m_display].themes[index].theme_name);
            }
            else
            {
                enabled = m_project->mDisplays[m_display].themes[index].gen_pixelmap_table;
            }

            if (enabled)
            {
                theme_info *ti = &m_project->mDisplays[m_display].themes[index];
                theme_info *refer_ti = &m_project->mDisplays[m_display].themes[theme];

                if ((info->palette_type == PALETTE_TYPE_SHARED) &&
                    ((ti->palette_predefined != refer_ti->palette_predefined) ||
                     (ti->palette_total_size != refer_ti->palette_total_size) ||
                     (memcmp(ti->palette, refer_ti->palette, sizeof(GX_COLOR) * ti->palette_total_size) != 0)))
                {
                    break;
                }

                res_id = m_project->GetResourceId(m_display, info);
                refer_info = m_project->FindResource(m_display, index, info->type, res_id);

                if (refer_info)
                {
                    abspath = MakeAbsolutePathname(info->pathinfo);
                    refer_abspath = MakeAbsolutePathname(refer_info->pathinfo);

                    if ((abspath == refer_abspath) &&
                        (info->output_color_format == refer_info->output_color_format) &&
                        (info->keep_alpha == refer_info->keep_alpha) &&
                        (info->dither == refer_info->dither))
                    {
                        refer_theme = index;
                    }
                }
                break;
            }
        }
        break;
    }

    return refer_theme;
}

///////////////////////////////////////////////////////////////////////////////
BOOL resource_gen::IsSystemPixelmap(INT pixelmap_id)
{
    CCommandInfo* pCmdInfo = GetCmdInfo();

    if (pCmdInfo->IsXmlMode())
    {
        return FALSE;
    }

    switch (pixelmap_id)
    {
    case GX_PIXELMAP_RADIO_ON_ID:
    case GX_PIXELMAP_RADIO_OFF_ID:
    case GX_PIXELMAP_CHECKBOX_ON_ID:
    case GX_PIXELMAP_CHECKBOX_OFF_ID:
        return TRUE;
    }

    return FALSE;
}

///////////////////////////////////////////////////////////////////////////////
BOOL resource_gen::IsResEnabled(res_info* info)
{
    if (info && info->enabled)
    {
        if ((!info->parent) || (info->parent->enabled))
        {
            return TRUE;
        }
    }

    return FALSE;
}